diff options
-rw-r--r-- | etc/couchdb/default.ini.tpl.in | 1 | ||||
-rw-r--r-- | share/www/script/test/rewrite.js | 30 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_rewrite.erl | 26 |
3 files changed, 39 insertions, 18 deletions
diff --git a/etc/couchdb/default.ini.tpl.in b/etc/couchdb/default.ini.tpl.in index d6f52096..fb88ba63 100644 --- a/etc/couchdb/default.ini.tpl.in +++ b/etc/couchdb/default.ini.tpl.in @@ -18,6 +18,7 @@ bind_address = 127.0.0.1 max_connections = 2048 authentication_handlers = {couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler} default_handler = {couch_httpd_db, handle_request} +secure_rewrites = true [log] file = %localstatelogdir%/couch.log diff --git a/share/www/script/test/rewrite.js b/share/www/script/test/rewrite.js index 848427be..d3888d9a 100644 --- a/share/www/script/test/rewrite.js +++ b/share/www/script/test/rewrite.js @@ -137,14 +137,7 @@ couchTests.rewrite = function(debug) { "query": { "key": [":a", ":b"] } - }, - - { - "from": "uuids", - "to": "../../../_uuids" } - - ], lists: { simpleForm: stringFun(function(head, req) { @@ -339,12 +332,29 @@ couchTests.rewrite = function(debug) { T(/Value: doc 4/.test(xhr.responseText)); // test path relative to server + designDoc.rewrites.push({ + "from": "uuids", + "to": "../../../_uuids" + }); + T(db.save(designDoc).ok); var xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_rewrite/uuids"); - T(xhr.status == 200); + T(xhr.status == 500); var result = JSON.parse(xhr.responseText); - T(result.uuids.length == 1); - var first = result.uuids[0]; + T(result.error == "insecure_rewrite_rule"); + + run_on_modified_server( + [{section: "httpd", + key: "secure_rewrites", + value: "false"}], + function() { + var xhr = CouchDB.request("GET", "/test_suite_db/_design/test/_rewrite/uuids?cache=bust"); + T(xhr.status == 200); + var result = JSON.parse(xhr.responseText); + T(result.uuids.length == 1); + var first = result.uuids[0]; + }); + }); }
\ No newline at end of file diff --git a/src/couchdb/couch_httpd_rewrite.erl b/src/couchdb/couch_httpd_rewrite.erl index 1e2a532f..c1869b5e 100644 --- a/src/couchdb/couch_httpd_rewrite.erl +++ b/src/couchdb/couch_httpd_rewrite.erl @@ -366,24 +366,34 @@ make_rule(Rule) -> parse_path(Path) -> {ok, SlashRE} = re:compile(<<"\\/">>), - path_to_list(re:split(Path, SlashRE), []). + path_to_list(re:split(Path, SlashRE), [], 0). %% @doc convert a path rule (from or to) to an erlang list %% * and path variable starting by ":" are converted %% in erlang atom. -path_to_list([], Acc) -> +path_to_list([], Acc, _DotDotCount) -> lists:reverse(Acc); -path_to_list([<<>>|R], Acc) -> - path_to_list(R, Acc); -path_to_list([<<"*">>|R], Acc) -> - path_to_list(R, [?MATCH_ALL|Acc]); -path_to_list([P|R], Acc) -> +path_to_list([<<>>|R], Acc, DotDotCount) -> + path_to_list(R, Acc, DotDotCount); +path_to_list([<<"*">>|R], Acc, DotDotCount) -> + path_to_list(R, [?MATCH_ALL|Acc], DotDotCount); +path_to_list([<<"..">>|R], Acc, DotDotCount) when DotDotCount == 2 -> + case couch_config:get("httpd", "secure_rewrites", "true") of + "false" -> + path_to_list(R, [<<"..">>|Acc], DotDotCount+1); + Else -> + ?LOG_INFO("insecure_rewrite_rule ~p blocked", [lists:reverse(Acc) ++ [<<"..">>] ++ R]), + throw({insecure_rewrite_rule, "too many ../.. segments"}) + end; +path_to_list([<<"..">>|R], Acc, DotDotCount) -> + path_to_list(R, [<<"..">>|Acc], DotDotCount+1); +path_to_list([P|R], Acc, DotDotCount) -> P1 = case P of <<":", Var/binary>> -> list_to_atom(binary_to_list(Var)); _ -> P end, - path_to_list(R, [P1|Acc]). + path_to_list(R, [P1|Acc], DotDotCount). encode_query(Props) -> Props1 = lists:foldl(fun ({K, V}, Acc) -> |