mirror of
https://github.com/samsonjs/http-cookie.git
synced 2026-04-27 14:57:46 +00:00
Treat comma as normal character in HTTP::Cookie.cookie_value_to_hash
As pointed out in CVE-2016-7401, treating comma in a Cookie header value as separator may cause security problems.
This commit is contained in:
parent
1c4a7bbe4b
commit
7f94a9e5d9
2 changed files with 25 additions and 13 deletions
|
|
@ -50,7 +50,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def scan_value
|
def scan_value(comma_as_separator = false)
|
||||||
''.tap { |s|
|
''.tap { |s|
|
||||||
case
|
case
|
||||||
when scan(/[^,;"]+/)
|
when scan(/[^,;"]+/)
|
||||||
|
|
@ -59,7 +59,9 @@ class HTTP::Cookie::Scanner < StringScanner
|
||||||
# RFC 6265 2.2
|
# RFC 6265 2.2
|
||||||
# A cookie-value may be DQUOTE'd.
|
# A cookie-value may be DQUOTE'd.
|
||||||
s << scan_dquoted
|
s << scan_dquoted
|
||||||
when check(/;|#{RE_COOKIE_COMMA}/o)
|
when check(/;/)
|
||||||
|
break
|
||||||
|
when comma_as_separator && check(RE_COOKIE_COMMA)
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
s << getch
|
s << getch
|
||||||
|
|
@ -68,12 +70,12 @@ class HTTP::Cookie::Scanner < StringScanner
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def scan_name_value
|
def scan_name_value(comma_as_separator = false)
|
||||||
name = scan_name
|
name = scan_name
|
||||||
if skip(/\=/)
|
if skip(/\=/)
|
||||||
value = scan_value
|
value = scan_value(comma_as_separator)
|
||||||
else
|
else
|
||||||
scan_value
|
scan_value(comma_as_separator)
|
||||||
value = nil
|
value = nil
|
||||||
end
|
end
|
||||||
[name, value]
|
[name, value]
|
||||||
|
|
@ -159,7 +161,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
||||||
|
|
||||||
skip_wsp
|
skip_wsp
|
||||||
|
|
||||||
name, value = scan_name_value
|
name, value = scan_name_value(true)
|
||||||
if value.nil?
|
if value.nil?
|
||||||
@logger.warn("Cookie definition lacks a name-value pair.") if @logger
|
@logger.warn("Cookie definition lacks a name-value pair.") if @logger
|
||||||
elsif name.empty?
|
elsif name.empty?
|
||||||
|
|
@ -176,7 +178,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
||||||
break
|
break
|
||||||
when skip(/;/)
|
when skip(/;/)
|
||||||
skip_wsp
|
skip_wsp
|
||||||
aname, avalue = scan_name_value
|
aname, avalue = scan_name_value(true)
|
||||||
next if aname.empty? || value.nil?
|
next if aname.empty? || value.nil?
|
||||||
aname.downcase!
|
aname.downcase!
|
||||||
case aname
|
case aname
|
||||||
|
|
@ -218,13 +220,12 @@ class HTTP::Cookie::Scanner < StringScanner
|
||||||
until eos?
|
until eos?
|
||||||
skip_wsp
|
skip_wsp
|
||||||
|
|
||||||
name, value = scan_name_value
|
# Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
|
||||||
|
name, value = scan_name_value(false)
|
||||||
|
|
||||||
yield name, value if value
|
yield name, value if value
|
||||||
|
|
||||||
# The comma is used as separator for concatenating multiple
|
skip(/;/)
|
||||||
# values of a header.
|
|
||||||
skip(/[;,]/)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -441,17 +441,28 @@ class TestHTTPCookie < Test::Unit::TestCase
|
||||||
['Bar', 'value 2'],
|
['Bar', 'value 2'],
|
||||||
['Baz', 'value3'],
|
['Baz', 'value3'],
|
||||||
['Bar', 'value"4'],
|
['Bar', 'value"4'],
|
||||||
|
['Quux', 'x, value=5'],
|
||||||
]
|
]
|
||||||
|
|
||||||
cookie_value = HTTP::Cookie.cookie_value(pairs.map { |name, value|
|
cookie_value = HTTP::Cookie.cookie_value(pairs.map { |name, value|
|
||||||
HTTP::Cookie.new(:name => name, :value => value)
|
HTTP::Cookie.new(:name => name, :value => value)
|
||||||
})
|
})
|
||||||
|
|
||||||
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"', cookie_value
|
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"; Quux="x, value=5"', cookie_value
|
||||||
|
|
||||||
hash = HTTP::Cookie.cookie_value_to_hash(cookie_value)
|
hash = HTTP::Cookie.cookie_value_to_hash(cookie_value)
|
||||||
|
|
||||||
assert_equal 3, hash.size
|
assert_equal pairs.map(&:first).uniq.size, hash.size
|
||||||
|
|
||||||
|
hash.each_pair { |name, value|
|
||||||
|
_, pvalue = pairs.assoc(name)
|
||||||
|
assert_equal pvalue, value
|
||||||
|
}
|
||||||
|
|
||||||
|
# Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
|
||||||
|
hash = HTTP::Cookie.cookie_value_to_hash('Quux=x, value=5; Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"')
|
||||||
|
|
||||||
|
assert_equal pairs.map(&:first).uniq.size, hash.size
|
||||||
|
|
||||||
hash.each_pair { |name, value|
|
hash.each_pair { |name, value|
|
||||||
_, pvalue = pairs.assoc(name)
|
_, pvalue = pairs.assoc(name)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue