Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Filter sensitive query string parameters in the log [#6244 state:comm…

…itted]

This provides more safety to applications that put secret information in the query string, such as API keys or SSO tokens.

Signed-off-by: Xavier Noria <fxn@hashref.com>
  • Loading branch information...
commit 68802d0fbe9d20ef8c5f6626d4b3279bd3a42d3e 1 parent 51a269b
@fxn fxn authored
View
2  actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.1.0 (unreleased)*
+* Sensitive query string parameters (specified in config.filter_parameters) will now be filtered out from the request paths in the log file. [Prem Sichanugrist, fxn]
+
* URL parameters which return false for to_param now appear in the query string (previously they were removed) [Andrew White]
* URL parameters which return nil for to_param are now removed from the query string [Andrew White]
View
21 actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -5,10 +5,10 @@
module ActionDispatch
module Http
# Allows you to specify sensitive parameters which will be replaced from
- # the request log by looking in all subhashes of the param hash for keys
- # to filter. If a block is given, each key and value of the parameter
- # hash and all subhashes is passed to it, the value or key can be replaced
- # using String#replace or similar method.
+ # the request log by looking in the query string of the request and all
+ # subhashes of the params hash to filter. If a block is given, each key and
+ # value of the params hash and all subhashes is passed to it, the value
+ # or key can be replaced using String#replace or similar method.
#
# Examples:
#
@@ -38,6 +38,11 @@ def filtered_env
@filtered_env ||= env_filter.filter(@env)
end
+ # Reconstructed a path with all sensitive GET parameters replaced.
+ def filtered_path
+ @filtered_path ||= query_string.empty? ? path : "#{path}?#{filtered_query_string}"
+ end
+
protected
def parameter_filter
@@ -52,6 +57,14 @@ def parameter_filter_for(filters)
@@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
end
+ KV_RE = '[^&;=]+'
+ PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
+ def filtered_query_string
+ query_string.gsub(PAIR_RE) do |_|
+ parameter_filter.filter([[$1, $2]]).first.join("=")
+ end
+ end
+
end
end
end
View
38 actionpack/test/dispatch/request_test.rb
@@ -518,6 +518,44 @@ def url_for(options = {})
assert_equal "1", request.params["step"]
end
+ test "filtered_path returns path with filtered query string" do
+ %w(; &).each do |sep|
+ request = stub_request('QUERY_STRING' => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep),
+ 'PATH_INFO' => '/authenticate',
+ 'action_dispatch.parameter_filter' => [:secret, :api_key])
+
+ path = request.filtered_path
+ assert_equal %w(/authenticate?username=sikachu secret=[FILTERED] api_key=[FILTERED]).join(sep), path
+ end
+ end
+
+ test "filtered_path should not unescape a genuine '[FILTERED]' value" do
+ request = stub_request('QUERY_STRING' => "secret=bd4f21f&genuine=%5BFILTERED%5D",
+ 'PATH_INFO' => '/authenticate',
+ 'action_dispatch.parameter_filter' => [:secret])
+
+ path = request.filtered_path
+ assert_equal "/authenticate?secret=[FILTERED]&genuine=%5BFILTERED%5D", path
+ end
+
+ test "filtered_path should preserve duplication of keys in query string" do
+ request = stub_request('QUERY_STRING' => "username=sikachu&secret=bd4f21f&username=fxn",
+ 'PATH_INFO' => '/authenticate',
+ 'action_dispatch.parameter_filter' => [:secret])
+
+ path = request.filtered_path
+ assert_equal "/authenticate?username=sikachu&secret=[FILTERED]&username=fxn", path
+ end
+
+ test "filtered_path should ignore searchparts" do
+ request = stub_request('QUERY_STRING' => "secret",
+ 'PATH_INFO' => '/authenticate',
+ 'action_dispatch.parameter_filter' => [:secret])
+
+ path = request.filtered_path
+ assert_equal "/authenticate?secret", path
+ end
+
protected
def stub_request(env = {})
View
2  railties/lib/rails/rack/logger.rb
@@ -19,7 +19,7 @@ def call(env)
def before_dispatch(env)
request = ActionDispatch::Request.new(env)
- path = request.fullpath
+ path = request.filtered_path
info "\n\nStarted #{request.request_method} \"#{path}\" " \
"for #{request.ip} at #{Time.now.to_default_s}"
Please sign in to comment.
Something went wrong with that request. Please try again.