From 759f5227f839ce492db6361a5b66efe29470bf72 Mon Sep 17 00:00:00 2001 From: Jonathan Hooper Date: Thu, 14 Sep 2017 16:53:44 -0500 Subject: [PATCH] Sanitize UTF8 characters from headers **Why**: Rack encodes headers into 8 bit ASCII which results in encoding compadibility errors futher down the stack when the app tries to manipulate them. This commit encodes the headers and replaces incompatible characters with `?` characters so the headers do not cause the app to respond with 500s. --- app/services/analytics.rb | 1 - lib/headers_filter.rb | 8 ++++++++ spec/features/visitors/i18n_spec.rb | 2 +- spec/lib/headers_filter_spec.rb | 10 ++++++++++ spec/requests/headers_spec.rb | 6 ++++++ 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/services/analytics.rb b/app/services/analytics.rb index 6d59735fcbe..220e1dc90e5 100644 --- a/app/services/analytics.rb +++ b/app/services/analytics.rb @@ -9,7 +9,6 @@ def track_event(event, attributes = {}) event_properties: attributes.except(:user_id), user_id: attributes[:user_id] || uuid, } - ahoy.track(event, analytics_hash.merge!(request_attributes)) end diff --git a/lib/headers_filter.rb b/lib/headers_filter.rb index 44e7cbd610d..061f33f59b7 100644 --- a/lib/headers_filter.rb +++ b/lib/headers_filter.rb @@ -12,10 +12,18 @@ def initialize(app) def call(env) HEADERS_TO_DELETE.each { |header| env.delete(header) } + ascii_encode_headers(env) app.call(env) end private + def ascii_encode_headers(env) + headers = env.select { |key, _value| key.starts_with? 'HTTP_' } + headers.each do |header, value| + env[header] = value.encode('ascii-8bit', invalid: :replace, undef: :replace, replace: '?') + end + end + attr_reader :app end diff --git a/spec/features/visitors/i18n_spec.rb b/spec/features/visitors/i18n_spec.rb index 3d28cc19c02..bd4f88e8ac7 100644 --- a/spec/features/visitors/i18n_spec.rb +++ b/spec/features/visitors/i18n_spec.rb @@ -10,7 +10,7 @@ context 'visit homepage with locale set in header' do before do - page.driver.header 'Accept-Language', locale + page.driver.header 'Accept-Language', locale.to_s visit root_path end diff --git a/spec/lib/headers_filter_spec.rb b/spec/lib/headers_filter_spec.rb index 7f83e12cc1a..eed59bd02f4 100644 --- a/spec/lib/headers_filter_spec.rb +++ b/spec/lib/headers_filter_spec.rb @@ -17,5 +17,15 @@ expect(env).to_not have_key('HTTP_HOST') expect(env).to_not have_key('HTTP_X_FORWARDED_HOST') end + + it 'encodes headers as 8 bit ASCII' do + env = { + 'HTTP_USER_AGENT' => 'Mózillá/5.0', + } + + middleware.call(env) + + expect(env['HTTP_USER_AGENT'].ascii_only?).to eq(true) + end end end diff --git a/spec/requests/headers_spec.rb b/spec/requests/headers_spec.rb index 9096eeee4fc..501de5e4e2e 100644 --- a/spec/requests/headers_spec.rb +++ b/spec/requests/headers_spec.rb @@ -24,4 +24,10 @@ expect(response.code.to_i).to eq(404) end + + it 'ASCII encodes UTF8 headers' do + get root_path, headers: { 'User-Agent' => 'Mózillá/5.0' } + + expect(request.env['HTTP_USER_AGENT'].ascii_only?).to eq(true) + end end