Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow scrub all parameters #431

Merged
merged 2 commits into from
Apr 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions lib/rollbar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@
require 'rollbar/lazy_store'

module Rollbar
ATTACHMENT_CLASSES = %w[
ActionDispatch::Http::UploadedFile
Rack::Multipart::UploadedFile
].freeze
PUBLIC_NOTIFIER_METHODS = %w(debug info warn warning error critical log logger
process_payload process_from_async_handler scope send_failsafe log_info log_debug
log_warning log_error silenced)
Expand Down
76 changes: 12 additions & 64 deletions lib/rollbar/request_data_extractor.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
require 'rack'
require 'tempfile'

require 'rollbar/scrubbers'
require 'rollbar/scrubbers/url'
require 'rollbar/scrubbers/params'
require 'rollbar/util/ip_obfuscator'

module Rollbar
module RequestDataExtractor
SKIPPED_CLASSES = [Tempfile]

def extract_person_data_from_controller(env)
if env.has_key? 'rollbar.person_data'
if env.has_key?('rollbar.person_data')
person_data = env['rollbar.person_data'] || {}
else
controller = env['action_controller.instance']
Expand Down Expand Up @@ -47,24 +47,16 @@ def extract_request_data_from_rack(env)
:cookies => cookies,
:session => session,
:method => rollbar_request_method(env),
:route => route_params,
:route => route_params
}

if env["action_dispatch.request_id"]
data[:request_id] = env["action_dispatch.request_id"]
if env['action_dispatch.request_id']
data[:request_id] = env['action_dispatch.request_id']
end

data
end

def rollbar_scrubbed(value)
if Rollbar.configuration.randomize_scrub_length
random_filtered_value
else
'*' * (value.length rescue 8)
end
end

private

def mergeable_raw_body_params(rack_req)
Expand All @@ -89,7 +81,7 @@ def rollbar_headers(env)
if name == 'Cookie'
{}
elsif sensitive_headers_list.include?(name)
{ name => rollbar_scrubbed(env[header]) }
{ name => Rollbar::Scrubbers.scrub_value(env[header]) }
else
{ name => env[header] }
end
Expand All @@ -108,8 +100,8 @@ def rollbar_url(env)

port = env['HTTP_X_FORWARDED_PORT']
if port && !(scheme.downcase == 'http' && port.to_i == 80) && \
!(scheme.downcase == 'https' && port.to_i == 443) && \
!(host.include? ':')
!(scheme.downcase == 'https' && port.to_i == 443) && \
!(host.include? ':')
host = host + ':' + port
end

Expand Down Expand Up @@ -151,7 +143,7 @@ def rollbar_raw_body_params(rack_req)

def json_request?(rack_req)
!!(rack_req.env['CONTENT_TYPE'] =~ %r{application/json} ||
rack_req.env['ACCEPT'] =~ /\bjson\b/)
rack_req.env['ACCEPT'] =~ /\bjson\b/)
end

def rollbar_request_params(env)
Expand Down Expand Up @@ -189,59 +181,15 @@ def rollbar_request_cookies(rack_req)
end

def rollbar_filtered_params(sensitive_params, params)
sensitive_params_regexp = Regexp.new(sensitive_params.map{ |val| Regexp.escape(val.to_s).to_s }.join('|'), true)

return {} unless params

params.to_hash.inject({}) do |result, (key, value)|
if sensitive_params_regexp =~ Rollbar::Encoding.encode(key).to_s
result[key] = rollbar_scrubbed(value)
elsif value.is_a?(Hash)
result[key] = rollbar_filtered_params(sensitive_params, value)
elsif value.is_a?(Array)
result[key] = value.map do |v|
v.is_a?(Hash) ? rollbar_filtered_params(sensitive_params, v) : rollbar_filtered_param_value(v)
end
elsif skip_value?(value)
result[key] = "Skipped value of class '#{value.class.name}'"
else
result[key] = rollbar_filtered_param_value(value)
end

result
end
end

def rollbar_filtered_param_value(value)
if ATTACHMENT_CLASSES.include?(value.class.name)
begin
{
:content_type => value.content_type,
:original_filename => value.original_filename,
:size => value.tempfile.size
}
rescue
'Uploaded file'
end
else
value
end
Rollbar::Scrubbers::Params.call(params, sensitive_params)
end

def sensitive_params_list(env)
Array(Rollbar.configuration.scrub_fields) | Array(env['action_dispatch.parameter_filter'])
Array(env['action_dispatch.parameter_filter'])
end

def sensitive_headers_list
Rollbar.configuration.scrub_headers || []
end

def random_filtered_value
'*' * (rand(5) + 3)
end

def skip_value?(value)
SKIPPED_CLASSES.any? { |klass| value.is_a?(klass) }
end
end
end
13 changes: 13 additions & 0 deletions lib/rollbar/scrubbers.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
module Rollbar
module Scrubbers
extend self

def scrub_value(value)
if Rollbar.configuration.randomize_scrub_length
random_filtered_value
else
'*' * (value.length rescue 8)
end
end

def random_filtered_value
'*' * (rand(5) + 3)
end
end
end
98 changes: 98 additions & 0 deletions lib/rollbar/scrubbers/params.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
require 'rollbar/scrubbers'

module Rollbar
module Scrubbers
# This class contains the logic to scrub the receive parameters. It will
# scrub the parameters matching Rollbar.configuration.scrub_fields Array.
# Also, if that configuration option is se to :scrub_all, it will scrub all
# received parameters
class Params
SKIPPED_CLASSES = [Tempfile]
ATTACHMENT_CLASSES = %w(ActionDispatch::Http::UploadedFile Rack::Multipart::UploadedFile).freeze
SCRUB_ALL = :scrub_all

def self.call(*args)
new.call(*args)
end

def call(params, extra_fields = [])
return {} unless params

config = Rollbar.configuration.scrub_fields

scrub(params, build_scrub_options(config, extra_fields))
end

private

def build_scrub_options(config, extra_fields)
ary_config = Array(config)

{
:fields_regex => build_fields_regex(ary_config, extra_fields),
:scrub_all => ary_config.include?(SCRUB_ALL)
}
end

def build_fields_regex(config, extra_fields)
fields = config.find_all { |f| f.is_a?(String) || f.is_a?(Symbol) }
fields += Array(extra_fields)

return unless fields.any?

Regexp.new(fields.map { |val| Regexp.escape(val.to_s).to_s }.join('|'), true)
end

def scrub(params, options)
fields_regex = options[:fields_regex]
scrub_all = options[:scrub_all]

params.to_hash.inject({}) do |result, (key, value)|
if value.is_a?(Hash)
result[key] = scrub(value, options)
elsif value.is_a?(Array)
result[key] = scrub_array(value, options)
elsif skip_value?(value)
result[key] = "Skipped value of class '#{value.class.name}'"
elsif fields_regex && fields_regex =~ Rollbar::Encoding.encode(key).to_s || scrub_all
result[key] = Rollbar::Scrubbers.scrub_value(value)
else
result[key] = rollbar_filtered_param_value(value)
end

result
end
end

def scrub_array(array, options)
array.map do |value|
value.is_a?(Hash) ? scrub(value, options) : rollbar_filtered_param_value(value)
end
end

def rollbar_filtered_param_value(value)
if ATTACHMENT_CLASSES.include?(value.class.name)
begin
attachment_value(value)
rescue
'Uploaded file'
end
else
value
end
end

def attachment_value(value)
{
:content_type => value.content_type,
:original_filename => value.original_filename,
:size => value.tempfile.size
}
end

def skip_value?(value)
SKIPPED_CLASSES.any? { |klass| value.is_a?(klass) }
end
end
end
end
26 changes: 0 additions & 26 deletions spec/rollbar/request_data_extractor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,4 @@ class ExtractorDummy
end
end
end

describe '#rollbar_scrubbed_value' do
context 'with random scrub length' do
before do
allow(Rollbar.configuration).to receive(:randomize_scrub_length).and_return(true)
end

let(:value) { 'herecomesaverylongvalue' }

it 'randomizes the scrubbed string' do
expect(subject.rollbar_scrubbed(value)).to match(/\*{3,8}/)
end
end

context 'with no-random scrub length' do
before do
allow(Rollbar.configuration).to receive(:randomize_scrub_length).and_return(false)
end

let(:value) { 'herecomesaverylongvalue' }

it 'randomizes the scrubbed string' do
expect(subject.rollbar_scrubbed(value)).to match(/\*{#{value.length}}/)
end
end
end
end
Loading