Skip to content

Commit de3e207

Browse files
committed
Fix "api_key" possibly getting stripped from inside URLs.
We want to strip the "api_key" query parameter, but our regex wasn't quite correct, so it was possible "api_key" was getting stripped from the URL in unexpected situations, like when the string "api_key" just happened to be somewhere inside the query string (for example, it would end up stripping "?foo=api_key" or ?api_key_foo=bar"). This fixes the issue by fixing the regex for stripping query parameters to more properly detect individual query string boundaries (so only "api_key=foo" should be stripped, but other instances of "api_key" should be left alone).
1 parent 1c64703 commit de3e207

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# API Umbrella Change Log
22

3+
## Unreleased
4+
5+
### Fixed
6+
7+
- **Fix URL handling for query strings containing "api\_key":** It was possible that API Umbrella was stripping the string "api\_key" from inside URLs before passing requests to the API backend in some unexpected cases. The `api_key` query parameter should still be stripped, but other instances of "api\_key" elsewhere in the URL (for example as a value, like `?foo=api_key`), are now retained.
8+
39
## 0.14.4 (2017-07-15)
410

511
This update contains one important fix for v0.14.3. Upgrading is recommended if you are currently running v0.14.3.

src/api-umbrella/proxy/utils.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ function _M.remove_arg(original_args, remove)
248248
-- matter, but in general it just seems safer to default to doing less
249249
-- changes to the query string).
250250
local _, gsub_err
251-
args, _, gsub_err = gsub(args, "\\b" .. remove .. "=?[^&]*(&|$)", "")
251+
args, _, gsub_err = gsub(args, "(?<=^|&)" .. remove .. "(?:=[^&]*)?(?:&|$)", "", "jo")
252252
if gsub_err then
253253
ngx.log(ngx.ERR, "regex error: ", gsub_err)
254254
end

test/proxy/request_rewriting/test_strips_api_keys.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def test_strips_api_key_from_middle_of_query
4343
assert_response_code(200, response)
4444
data = MultiJson.load(response.body)
4545
assert_equal({ "test" => "value", "foo" => "bar" }, data["url"]["query"])
46+
assert_equal("http://127.0.0.1/info/?test=value&foo=bar", data["raw_url"])
4647
end
4748

4849
def test_strips_repeated_api_key_in_query
@@ -100,6 +101,41 @@ def test_retains_basic_auth_if_api_key_passed_by_other_means
100101
assert(data["headers"]["authorization"])
101102
end
102103

104+
def test_retains_api_key_string_in_values
105+
response = Typhoeus.get("http://127.0.0.1:9080/api/info/?search=api_key", http_options)
106+
assert_response_code(200, response)
107+
data = MultiJson.load(response.body)
108+
assert_equal({ "search" => "api_key" }, data["url"]["query"])
109+
end
110+
111+
def test_retains_api_key_string_in_values_with_prefix
112+
response = Typhoeus.get("http://127.0.0.1:9080/api/info/?search=foo_api_key", http_options)
113+
assert_response_code(200, response)
114+
data = MultiJson.load(response.body)
115+
assert_equal({ "search" => "foo_api_key" }, data["url"]["query"])
116+
end
117+
118+
def test_retains_api_key_string_in_values_with_suffix
119+
response = Typhoeus.get("http://127.0.0.1:9080/api/info/?search=api_key_foo", http_options)
120+
assert_response_code(200, response)
121+
data = MultiJson.load(response.body)
122+
assert_equal({ "search" => "api_key_foo" }, data["url"]["query"])
123+
end
124+
125+
def test_retains_api_key_string_in_param_with_prefix
126+
response = Typhoeus.get("http://127.0.0.1:9080/api/info/?foo_api_key=bar", http_options)
127+
assert_response_code(200, response)
128+
data = MultiJson.load(response.body)
129+
assert_equal({ "foo_api_key" => "bar" }, data["url"]["query"])
130+
end
131+
132+
def test_retains_api_key_string_in_param_with_suffix
133+
response = Typhoeus.get("http://127.0.0.1:9080/api/info/?api_key_foo=bar", http_options)
134+
assert_response_code(200, response)
135+
data = MultiJson.load(response.body)
136+
assert_equal({ "api_key_foo" => "bar" }, data["url"]["query"])
137+
end
138+
103139
def test_preserves_query_string_order
104140
response = Typhoeus.get("http://127.0.0.1:9080/api/info/?ccc=foo&aaa=bar&api_key=#{self.api_key}&b=test", http_options)
105141
assert_response_code(200, response)

0 commit comments

Comments
 (0)