Skip to content

Commit

Permalink
Add sanitization of cookie header.
Browse files Browse the repository at this point in the history
  • Loading branch information
whitequark committed May 29, 2018
2 parents e05853c + 2ba7079 commit 488d680
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
17 changes: 16 additions & 1 deletion lib/rack/utf8_sanitizer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def call(env)

def sanitize(env)
sanitize_rack_input(env)
sanitize_cookies(env)
env.each do |key, value|
next if skip?(key)

Expand Down Expand Up @@ -105,7 +106,7 @@ def sanitize_rack_input(env)
return unless @sanitizable_content_types.any? {|type| content_type == type }
uri_encoded = URI_ENCODED_CONTENT_TYPES.any? {|type| content_type == type}

if env["rack.input"]
if env['rack.input']
sanitized_input = sanitize_io(env['rack.input'], uri_encoded)

env['rack.input'] = sanitized_input
Expand Down Expand Up @@ -159,6 +160,20 @@ def sanitize_io(io, uri_encoded = false)
SanitizedRackInput.new(io, StringIO.new(sanitized_input))
end

# Cookies need to be split and then sanitized as url encoded strings
# since the cookie string itself is not url encoded (separated by `;`),
# and the normal method of `sanitize_uri_encoded_string` would break
# later cookie parsing in the case that a cookie value contained an
# encoded `;`.
def sanitize_cookies(env)
return unless env['HTTP_COOKIE']

env['HTTP_COOKIE'] = env['HTTP_COOKIE']
.split(/[;,] */n)
.map { |cookie| sanitize_uri_encoded_string(cookie) }
.join('; ')
end

# URI.encode/decode expect the input to be in ASCII-8BIT.
# However, there could be invalid UTF-8 characters both in
# raw and percent-encoded form.
Expand Down
28 changes: 28 additions & 0 deletions test/test_utf8_sanitizer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,34 @@ def sanitize_form_data(request_env = request_env())
end
end

describe "with custom content-type" do
def request_env
{
"REQUEST_METHOD" => "GET",
"CONTENT_TYPE" => "application/json",
"HTTP_COOKIE" => @cookie,
"rack.input" => StringIO.new,
}
end

it "sanitizes bad http cookie" do
@cookie = "foo=bla; quux=bar\xED"
response_env = @app.(request_env)
response_env['HTTP_COOKIE'].should != @cookie
response_env['HTTP_COOKIE'].should == 'foo=bla; quux=bar%EF%BF%BD'
end

it "does not change ok http cookie" do
@cookie = "foo=bla; quux=bar"
response_env = @app.(request_env)
response_env['HTTP_COOKIE'].should == @cookie

@cookie = "foo=b%3bla; quux=b%20a%20r"
response_env = @app.(request_env)
response_env['HTTP_COOKIE'].should == @cookie
end
end

describe "with custom content-type" do
def request_env
@plain_input = "foo bar лол".force_encoding('UTF-8')
Expand Down

0 comments on commit 488d680

Please sign in to comment.