Skip to content

Conversation

@ioquatix
Copy link
Member

@ioquatix ioquatix commented Jun 5, 2024

This is a follow up to #2188 which removes all cookie key escaping/unescaping.

This is better aligned with how JavaScript's document.cookies interface works, and I think will reduce complexity and potential confusion. It may introduce some compatibility issues, but the scenario we are breaking is already explicitly documented here

rack/lib/rack/utils.rb

Lines 250 to 251 in 8d7c029

# Generate an encoded string using the provided +key+ and +value+ suitable
# for the +set-cookie+ header according to RFC6265. The +value+ may be an
and users who hit this limitation are already operating in a grey area (not following the requirements of the documentation, and the cookies being set won't have the same name when read back).

@ioquatix ioquatix force-pushed the cookie-key-remove-escaping branch from 6a5078f to ef70646 Compare June 5, 2024 07:09
@ioquatix ioquatix requested a review from jeremyevans June 5, 2024 07:13
Copy link
Contributor

@jeremyevans jeremyevans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend @tenderlove review for security.

Assuming no security issues, due to backwards compatibility issues, this should probably wait until Rack 4.

The commit message mentions unescaping, but nothing in the patch removes unescaping.

@ioquatix
Copy link
Member Author

ioquatix commented Jun 5, 2024

@jeremyevans I'm not sure I completely follow your feedback.

#2188 which is not merged, implements symmetric escape/unescape except where it's a known security issue.

This PR adds a 2nd commit on top of that, which removes escape/unescape entirely, for the reasons outlined. I don't think the compatibility issue will be huge (no more than others we accept in minor releases), but I am okay with merging #2188 and as a follow up we can consider merging this PR.

@jeremyevans
Copy link
Contributor

I guess I expect more compatibility issues than you do. My expectation is there are users relying on the current behavior, and rejecting cookie keys previously not rejected will break their apps. When we made the change to not to unescape cookies due to the security issues, we broke a significant amount of apps, and this change seems as likely to cause issues.

Maybe the PR description makes sense as a commit message to the second commit. But in terms of the whole PR, this doesn't deal with unescaping.

@ioquatix
Copy link
Member Author

ioquatix commented Jun 5, 2024

I guess I expect more compatibility issues than you do. My expectation is there are users relying on the current behavior, and rejecting cookie keys previously not rejected will break their apps. When we made the change to not to unescape cookies due to the security issues, we broke a significant amount of apps, and this change seems as likely to cause issues.

I agree, it may. Do you have any reference to the previous issues we encountered?

@jeremyevans
Copy link
Contributor

Looks like cookie keys have always been escaped, dating to the initial import (7ed819a).

Unescaping of keys was the cause of CVE-2020-8184 (1f5763d).

I think that's why we are in the situation we are currently in, where keys are escaped when serializing but not unescaped when deserializing. Users do try to use cookie key names that require escaping (e.g. #1674). Since Rack's introduction, that worked fine because Rack did the escaping. If Rack stops doing escaping, and instead raises an exception, such code will break.

Note that the validation regexp used here I don't think is complete. It doesn't validate % escapes, for example, so it will treat invalid escapes in cookie keys as valid.

@ioquatix
Copy link
Member Author

ioquatix commented Jun 5, 2024

Escaping cookie keys is a rack invention, it's not standard and there is no standard interpretation of percent escapes for the cookie key except for the raw strings. The escaped cookie keys will show up in document.cookies in the escaped form. According to TOKEN, % is not a special character, so there is no reason it can't be part of the cookie key.

Example server:

run do |env|
	[200, {'set-cookie' => '%66oo=bar'}, ["Hello World!"]]
end

Browser shows:

image

And on subsequent requests, we see:

 "HTTP_COOKIE"=>"%66oo=bar",

Rack should never have escaped cookie keys - it's non-standard and the un-escaped name won't match subsequent cookie header keys.

Finally, without symmetry, I simply don't understand how anyone is supposed to use this API...

e.g. for a cookie key that will be escaped, how can this interface work???

KEY = 'my cookie'

run do |env|
	request = Rack::Request.new(env)
	puts "My Cookie: #{request.cookies[KEY]}" # always empty!
	puts "All Cookies: #{request.cookies}"
	
	headers = {}
	Rack::Utils.set_cookie_header!(headers, KEY, 'bar')
	
	[200, headers, ["Hello World!"]]
end

@jeremyevans
Copy link
Contributor

Thanks for that information. I'm OK with a deprecation warning for keys that need escaping in Rack 3.1, and removal in Rack 3.2.

@ioquatix
Copy link
Member Author

ioquatix commented Jun 5, 2024

That seems reasonable to me.

@ioquatix
Copy link
Member Author

ioquatix commented Jun 6, 2024

Closing in favour of #2191.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants