From 4827d5db5fb2ca10772f70fbb6ad7f7f99285d96 Mon Sep 17 00:00:00 2001 From: Michael Santos Date: Mon, 21 Feb 2011 13:53:56 -0500 Subject: inets: prevent XSS in error pages Prevent user controlled input from being interpreted as HTML in error pages by encoding the reserved HTML characters. The reserved character set should be safe for displaying data within the body of HTML pages as outlined here: http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet Previously, weird URLs were URI encoded in the error page. This worked quite well but the URL would be displayed in the HTML in percent encoded format. There was also a check for URIs that were already escaped (by the browser) that would fail if the browser sent an URI containing a "%", e.g.: w3m "http://localhost:8080/foo?%" Also encode the HTTP method and version, since it's possible they may be manipulated: FOO /index.html HTTP/1.0 GET /index.html foo/1.0 Encode the static messages to prevent characters from being interpreted as HTML such as "heavy load (>~w processes)". --- lib/inets/src/http_server/httpd_util.erl | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'lib/inets/src/http_server') diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl index 789f12652b..c1aff65d5e 100644 --- a/lib/inets/src/http_server/httpd_util.erl +++ b/lib/inets/src/http_server/httpd_util.erl @@ -181,7 +181,7 @@ message(304, _URL,_) -> message(400,none,_) -> "Your browser sent a query that this server could not understand."; message(400,Msg,_) -> - "Your browser sent a query that this server could not understand. "++ maybe_encode(Msg); + "Your browser sent a query that this server could not understand. "++ http_util:html_encode(Msg); message(401,none,_) -> "This server could not verify that you are authorized to access the document you @@ -190,48 +190,48 @@ credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required."; message(403,RequestURI,_) -> - "You don't have permission to access "++ maybe_encode(RequestURI) ++" on this server."; + "You don't have permission to access "++ http_util:html_encode(RequestURI) ++" on this server."; message(404,RequestURI,_) -> - "The requested URL " ++ maybe_encode(RequestURI) ++ " was not found on this server."; + "The requested URL " ++ http_util:html_encode(RequestURI) ++ " was not found on this server."; message(408, Timeout, _) -> Timeout; message(412,none,_) -> - "The requested preconditions where false"; + "The requested preconditions were false"; message(413, Reason,_) -> - "Entity: " ++ Reason; + "Entity: " ++ http_util:html_encode(Reason); message(414,ReasonPhrase,_) -> - "Message "++ ReasonPhrase ++"."; + "Message "++ http_util:html_encode(ReasonPhrase) ++"."; message(416,ReasonPhrase,_) -> - ReasonPhrase; + http_util:html_encode(ReasonPhrase); message(500,_,ConfigDB) -> ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"), "The server encountered an internal error or " "misconfiguration and was unable to complete " "your request.

Please contact the server administrator " - ++ ServerAdmin ++ ", and inform them of the time the error occurred " + ++ http_util:html_encode(ServerAdmin) ++ ", and inform them of the time the error occurred " "and anything you might have done that may have caused the error."; message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) -> if is_atom(Method) -> - atom_to_list(Method)++ - " to "++ maybe_encode(RequestURI)++" ("++HTTPVersion++") not supported."; + http_util:html_encode(atom_to_list(Method))++ + " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported."; is_list(Method) -> - Method++ - " to "++ maybe_encode(RequestURI)++" ("++HTTPVersion++") not supported." + http_util:html_encode(Method)++ + " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported." end; message(503, String, _ConfigDB) -> - "This service in unavailable due to: "++String. + "This service in unavailable due to: "++ http_util:html_encode(String). maybe_encode(URI) -> - case lists:member($%, URI) of - true -> - URI; - false -> - http_uri:encode(URI) - end. + Decoded = try http_uri:decode(URI) of + N -> N + catch + error:_ -> URI + end, + http_uri:encode(Decoded). %%convert_rfc_date(Date)->{{YYYY,MM,DD},{HH,MIN,SEC}} -- cgit v1.2.3 From 73f261d2f44a58fda92e3d6e035051c11c3e4521 Mon Sep 17 00:00:00 2001 From: Bernard Duggan Date: Wed, 23 Feb 2011 15:55:37 +1100 Subject: Modify mod_esi:deliver/2 to accept binary data This change allows for more efficient delivery of large amounts of data through the mod_esi interface when the handling process has that data in binary format. It avoids the need to convert to list and the extra memory involved in passing that list between processes. --- lib/inets/src/http_server/mod_esi.erl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/inets/src/http_server') diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl index 929185a67a..b85c479693 100644 --- a/lib/inets/src/http_server/mod_esi.erl +++ b/lib/inets/src/http_server/mod_esi.erl @@ -452,6 +452,10 @@ handle_body(Pid, ModData, Body, Timeout, Size, IsDisableChunkedSend) -> ?hdrt("handle_body - send chunk", [{timeout, Timeout}, {size, Size}]), httpd_response:send_chunk(ModData, Body, IsDisableChunkedSend), receive + {esi_data, Data} when is_binary(Data) -> + ?hdrt("handle_body - received binary data (esi)", []), + handle_body(Pid, ModData, Data, Timeout, Size + byte_size(Data), + IsDisableChunkedSend); {esi_data, Data} -> ?hdrt("handle_body - received data (esi)", []), handle_body(Pid, ModData, Data, Timeout, Size + length(Data), -- cgit v1.2.3 From cbe8b2e034a8b2cd6052df5e27f1b229ded9748e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Catalinas=20Jim=C3=A9nez?= Date: Thu, 17 Mar 2011 01:30:51 +0100 Subject: Fix log messages formating in httpd --- lib/inets/src/http_server/httpd_file.erl | 15 +++++++-------- lib/inets/src/http_server/httpd_log.erl | 2 +- lib/inets/src/http_server/httpd_request_handler.erl | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'lib/inets/src/http_server') diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl index 7e21d9e158..dc1dae8bc9 100644 --- a/lib/inets/src/http_server/httpd_file.erl +++ b/lib/inets/src/http_server/httpd_file.erl @@ -26,22 +26,21 @@ handle_error(eacces, Op, ModData, Path) -> - handle_error(403, Op, ModData, Path,"Forbidden"); + handle_error(403, Op, ModData, Path, ": Forbidden"); handle_error(enoent, Op, ModData, Path) -> - handle_error(404, Op, ModData, Path,"File not found"); + handle_error(404, Op, ModData, Path, ": File not found"); handle_error(enotdir, Op, ModData, Path) -> handle_error(404, Op, ModData, Path, - ": A component of the file name is not a directory"); + ": A component of the file name is not a directory"); handle_error(emfile, Op, _ModData, Path) -> handle_error(500, Op, none, Path, ": To many open files"); handle_error({enfile,_}, Op, _ModData, Path) -> handle_error(500, Op, none, Path, ": File table overflow"); handle_error(_Reason, Op, ModData, Path) -> - handle_error(404, Op, ModData, Path, "File not found"). - -handle_error(StatusCode, Op, none, Path, Reason) -> - {StatusCode, none, ?NICE("Can't " ++ Op ++ Path ++ Reason)}; + handle_error(404, Op, ModData, Path, ": File not found"). +handle_error(StatusCode, Op, none, Path, Reason) -> + {StatusCode, none, ?NICE("Can't " ++ Op ++ " " ++ Path ++ Reason)}; handle_error(StatusCode, Op, ModData, Path, Reason) -> {StatusCode, ModData#mod.request_uri, - ?NICE("Can't " ++ Op ++ Path ++ Reason)}. + ?NICE("Can't " ++ Op ++ " " ++ Path ++ Reason)}. diff --git a/lib/inets/src/http_server/httpd_log.erl b/lib/inets/src/http_server/httpd_log.erl index f3ea3aa0e2..4b0f49d560 100644 --- a/lib/inets/src/http_server/httpd_log.erl +++ b/lib/inets/src/http_server/httpd_log.erl @@ -113,7 +113,7 @@ do_error_entry(ConfigDB, RemoteHost, undefined, Date, Reason) -> do_error_entry(ConfigDB, RemoteHost, URI, Date, Reason) -> case httpd_util:lookup(ConfigDB, error_log_format, pretty) of pretty -> - io_lib:format("[~s] access to ~s failed for ~s reason: ~n~p~n", + io_lib:format("[~s] access to ~s failed for ~s, reason: ~n~p~n", [Date, URI, RemoteHost, Reason]); compact -> io_lib:format( "[~s] access to ~s failed for ~s, reason: ~w~n", diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index a9db6e2058..31ec416b2d 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -240,13 +240,13 @@ handle_info({ssl_error, _, _} = Reason, State) -> %% Timeouts handle_info(timeout, #state{mod = ModData, mfa = {_, parse, _}} = State) -> - error_log("No request received on keep-alive connection" + error_log("No request received on keep-alive connection " "before server side timeout", ModData), %% No response should be sent! {stop, normal, State#state{response_sent = true}}; handle_info(timeout, #state{mod = ModData} = State) -> httpd_response:send_status(ModData, 408, "Request timeout"), - error_log("The client did not send the whole request before the" + error_log("The client did not send the whole request before the " "server side timeout", ModData), {stop, normal, State#state{response_sent = true}}; -- cgit v1.2.3 From eea0a7bdf77179c98e41f867398253c4c6f0811f Mon Sep 17 00:00:00 2001 From: Bernard Duggan Date: Thu, 17 Mar 2011 12:18:29 +1100 Subject: Fix timeout message generated by mod_esi When a mod_esi request times out, the code to send a timeout response was incorrect and generated an internal server error as well as an invalid response line. --- lib/inets/src/http_server/mod_esi.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/inets/src/http_server') diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl index 929185a67a..a8e3b4ab47 100644 --- a/lib/inets/src/http_server/mod_esi.erl +++ b/lib/inets/src/http_server/mod_esi.erl @@ -415,7 +415,7 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) -> end; timeout -> ?hdrv("deliver_webpage_chunk - timeout", []), - send_headers(ModData, {504, "Timeout"},[{"connection", "close"}]), + send_headers(ModData, 504, [{"connection", "close"}]), httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket), process_flag(trap_exit,false), {proceed,[{response, {already_sent, 200, 0}} | ModData#mod.data]} -- cgit v1.2.3 From a0ab2e0fa31a2599d0532ef87c944837e96153c0 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 28 Mar 2011 14:07:44 +0200 Subject: A slightly more usefull debug printout (including httpd services). --- lib/inets/src/http_server/httpd_sup.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/inets/src/http_server') diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index f94e5459c1..b248c9bcf0 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -90,7 +90,7 @@ id(Address, Port) -> %%% Supervisor callback %%%========================================================================= init([HttpdServices]) -> - ?hdrd("starting", []), + ?hdrd("starting", [{httpd_service, HttpdServices}]), RestartStrategy = one_for_one, MaxR = 10, MaxT = 3600, -- cgit v1.2.3 From 7861327b7830c64675dd73d424de7d62007fd5a0 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 6 Apr 2011 17:40:42 +0200 Subject: Accepting file descriptors (fd) in the config for socket type ip_comm. --- lib/inets/src/http_server/httpd_sup.erl | 45 ++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'lib/inets/src/http_server') diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index b248c9bcf0..d028a19bf0 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -182,24 +182,32 @@ httpd_child_spec(ConfigFile, AcceptTimeout, Debug) -> Error end. -httpd_child_spec(Config, AcceptTimeout, Debug, Addr, 0) -> - case start_listen(Addr, 0, Config) of - {Pid, {NewPort, NewConfig, ListenSocket}} -> - Name = {httpd_instance_sup, Addr, NewPort}, - StartFunc = {httpd_instance_sup, start_link, - [NewConfig, AcceptTimeout, - {Pid, ListenSocket}, Debug]}, - Restart = permanent, - Shutdown = infinity, - Modules = [httpd_instance_sup], - Type = supervisor, - {Name, StartFunc, Restart, Shutdown, Type, Modules}; - {Pid, {error, Reason}} -> - exit(Pid, normal), - {error, Reason} - end; - httpd_child_spec(Config, AcceptTimeout, Debug, Addr, Port) -> + case Port == 0 orelse proplists:is_defined(fd, Config) of + true -> + httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port); + false -> + httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port) + end. + +httpd_child_spec_listen(Config, AcceptTimeout, Debug, Addr, Port) -> + case start_listen(Addr, Port, Config) of + {Pid, {NewPort, NewConfig, ListenSocket}} -> + Name = {httpd_instance_sup, Addr, NewPort}, + StartFunc = {httpd_instance_sup, start_link, + [NewConfig, AcceptTimeout, + {Pid, ListenSocket}, Debug]}, + Restart = permanent, + Shutdown = infinity, + Modules = [httpd_instance_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}; + {Pid, {error, Reason}} -> + exit(Pid, normal), + {error, Reason} + end. + +httpd_child_spec_nolisten(Config, AcceptTimeout, Debug, Addr, Port) -> Name = {httpd_instance_sup, Addr, Port}, StartFunc = {httpd_instance_sup, start_link, [Config, AcceptTimeout, Debug]}, @@ -224,7 +232,8 @@ listen(Address, Port, Config) -> SocketType = proplists:get_value(socket_type, Config, ip_comm), case http_transport:start(SocketType) of ok -> - case http_transport:listen(SocketType, Address, Port) of + Fd = proplists:get_value(fd, Config), + case http_transport:listen(SocketType, Address, Port, Fd) of {ok, ListenSocket} -> NewConfig = proplists:delete(port, Config), {ok, NewPort} = inet:port(ListenSocket), -- cgit v1.2.3