summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--etc/couchdb/default.ini.tpl.in1
-rw-r--r--share/www/script/test/rewrite.js30
-rw-r--r--src/couchdb/couch_httpd_rewrite.erl26
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) ->