Skip to content

Commit a425cd1

Browse files
Rich Cavanaughjeremy
authored andcommitted
Don't double-escape cookie store data. Don't split cookie values with newlines into an array. [#130 state:resolved]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
1 parent cde6a25 commit a425cd1

File tree

4 files changed

+26
-6
lines changed

4 files changed

+26
-6
lines changed

actionpack/lib/action_controller/cgi_ext/cookie.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def initialize(name = '', *value)
3737
@path = nil
3838
else
3939
@name = name['name']
40-
@value = Array(name['value'])
40+
@value = name['value'].kind_of?(String) ? [name['value']] : Array(name['value'])
4141
@domain = name['domain']
4242
@expires = name['expires']
4343
@secure = name['secure'] || false

actionpack/lib/action_controller/session/cookie_store.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,20 @@ def generate_digest(data)
130130
# Marshal a session hash into safe cookie data. Include an integrity hash.
131131
def marshal(session)
132132
data = ActiveSupport::Base64.encode64(Marshal.dump(session)).chop
133-
CGI.escape "#{data}--#{generate_digest(data)}"
133+
"#{data}--#{generate_digest(data)}"
134134
end
135135

136136
# Unmarshal cookie data to a hash and verify its integrity.
137137
def unmarshal(cookie)
138138
if cookie
139-
data, digest = CGI.unescape(cookie).split('--')
140-
unless digest == generate_digest(data)
139+
data, digest = cookie.split('--')
140+
141+
# Do two checks to transparently support old double-escaped data.
142+
unless digest == generate_digest(data) || digest == generate_digest(data = CGI.unescape(data))
141143
delete
142144
raise TamperedWithCookie
143145
end
146+
144147
Marshal.load(ActiveSupport::Base64.decode64(data))
145148
end
146149
end

actionpack/test/controller/cookie_test.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,9 @@ def test_cookies_should_not_be_split_on_ampersand_values
137137
cookies = CGI::Cookie.parse('return_to=http://rubyonrails.org/search?term=api&scope=all&global=true')
138138
assert_equal({"return_to" => ["http://rubyonrails.org/search?term=api&scope=all&global=true"]}, cookies)
139139
end
140+
141+
def test_cookies_should_not_be_split_on_values_with_newlines
142+
cookies = CGI::Cookie.new("name" => "val", "value" => "this\nis\na\ntest")
143+
assert cookies.size == 1
144+
end
140145
end

actionpack/test/controller/session/cookie_store_test.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ def self.cookies
4343
{ :empty => ['BAgw--0686dcaccc01040f4bd4f35fe160afe9bc04c330', {}],
4444
:a_one => ['BAh7BiIGYWkG--5689059497d7f122a7119f171aef81dcfd807fec', { 'a' => 1 }],
4545
:typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--9d20154623b9eeea05c62ab819be0e2483238759', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
46-
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }] }
46+
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }],
47+
:double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf'), { 'user_id' => 123, 'flash' => {} }] }
48+
4749
end
4850

4951
def setup
@@ -101,6 +103,15 @@ def test_restore_deletes_tampered_cookies
101103
end
102104
end
103105

106+
def test_restores_double_encoded_cookies
107+
set_cookie! cookie_value(:double_escaped)
108+
new_session do |session|
109+
session.dbman.restore
110+
assert_equal session["user_id"], 123
111+
assert_equal session["flash"], {}
112+
end
113+
end
114+
104115
def test_close_doesnt_write_cookie_if_data_is_blank
105116
new_session do |session|
106117
assert_no_cookies session
@@ -241,6 +252,7 @@ def self.cookies
241252
{ :empty => ['BAgw--0415cc0be9579b14afc22ee2d341aa21', {}],
242253
:a_one => ['BAh7BiIGYWkG--5a0ed962089cc6600ff44168a5d59bc8', { 'a' => 1 }],
243254
:typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--f426763f6ef435b3738b493600db8d64', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
244-
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }] }
255+
:flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }],
256+
:double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51'), { 'user_id' => 123, 'flash' => {} }] }
245257
end
246258
end

0 commit comments

Comments
 (0)