diff options
author | Loïc Hoguin <[email protected]> | 2019-09-07 12:18:16 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2019-09-07 12:18:16 +0200 |
commit | 4427108b69fcd1e6a8233a217fa0e99d0564b714 (patch) | |
tree | 17f211a65ab85db82b312129782e8024c5639fa7 /src/cowboy_static.erl | |
parent | 36836594f83a9dfdb30472a792d7ff73b3b48e3e (diff) | |
download | cowboy-4427108b69fcd1e6a8233a217fa0e99d0564b714.tar.gz cowboy-4427108b69fcd1e6a8233a217fa0e99d0564b714.tar.bz2 cowboy-4427108b69fcd1e6a8233a217fa0e99d0564b714.zip |
Improve the cowboy_static consistency across platforms
As a result we explictly reject path_info components that include
a forward slash, backward slash or NUL character. This only applies
to the [...] part of the path for dir/priv_dir configuration.
Also improve the tests so that they work on Windows.
Diffstat (limited to 'src/cowboy_static.erl')
-rw-r--r-- | src/cowboy_static.erl | 70 |
1 files changed, 43 insertions, 27 deletions
diff --git a/src/cowboy_static.erl b/src/cowboy_static.erl index d6ef45c..b0cf146 100644 --- a/src/cowboy_static.erl +++ b/src/cowboy_static.erl @@ -119,35 +119,51 @@ init_dir(Req, Path, HowToAccess, Extra) when is_list(Path) -> init_dir(Req, list_to_binary(Path), HowToAccess, Extra); init_dir(Req, Path, HowToAccess, Extra) -> Dir = fullpath(filename:absname(Path)), - PathInfo = cowboy_req:path_info(Req), - Filepath = filename:join([Dir|escape_reserved(PathInfo)]), - Len = byte_size(Dir), - case fullpath(Filepath) of - << Dir:Len/binary, $/, _/binary >> -> - init_info(Req, Filepath, HowToAccess, Extra); - << Dir:Len/binary >> -> - init_info(Req, Filepath, HowToAccess, Extra); - _ -> - {cowboy_rest, Req, error} + case cowboy_req:path_info(Req) of + %% When dir/priv_dir are used and there is no path_info + %% this is a configuration error and we abort immediately. + undefined -> + {ok, cowboy_req:reply(500, Req), error}; + PathInfo -> + case validate_reserved(PathInfo) of + error -> + {cowboy_rest, Req, error}; + ok -> + Filepath = filename:join([Dir|PathInfo]), + Len = byte_size(Dir), + case fullpath(Filepath) of + << Dir:Len/binary, $/, _/binary >> -> + init_info(Req, Filepath, HowToAccess, Extra); + << Dir:Len/binary >> -> + init_info(Req, Filepath, HowToAccess, Extra); + _ -> + {cowboy_rest, Req, error} + end + end end. -escape_reserved([]) -> []; -escape_reserved([P|Tail]) -> [escape_reserved(P, <<>>)|escape_reserved(Tail)]. +validate_reserved([]) -> + ok; +validate_reserved([P|Tail]) -> + case validate_reserved1(P) of + ok -> validate_reserved(Tail); + error -> error + end. -%% We escape the slash found in path segments because -%% a segment corresponds to a directory entry, and -%% therefore those slashes are expected to be part of -%% the directory name. -%% -%% Note that on most systems the slash is prohibited -%% and cannot appear in filenames, which means the -%% requested file will end up being not found. -escape_reserved(<<>>, Acc) -> - Acc; -escape_reserved(<< $/, Rest/bits >>, Acc) -> - escape_reserved(Rest, << Acc/binary, $\\, $/ >>); -escape_reserved(<< C, Rest/bits >>, Acc) -> - escape_reserved(Rest, << Acc/binary, C >>). +%% We always reject forward slash, backward slash and NUL as +%% those have special meanings across the supported platforms. +%% We could support the backward slash on some platforms but +%% for the sake of consistency and simplicity we don't. +validate_reserved1(<<>>) -> + ok; +validate_reserved1(<<$/, _/bits>>) -> + error; +validate_reserved1(<<$\\, _/bits>>) -> + error; +validate_reserved1(<<0, _/bits>>) -> + error; +validate_reserved1(<<_, Rest/bits>>) -> + validate_reserved1(Rest). fullpath(Path) -> fullpath(filename:split(Path), []). @@ -290,7 +306,7 @@ bad_path_win32_check_test_() -> -endif. %% Reject requests that tried to access a file outside -%% the target directory. +%% the target directory, or used reserved characters. -spec malformed_request(Req, State) -> {boolean(), Req, State}. |