-
Notifications
You must be signed in to change notification settings - Fork 21.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't change the default session serializer (Marshal) #12881
Comments
Ideally we'd have the option, default new apps to JSON and document the reasons you may want to flip to something else (in particular, people store objects in the session which aren't roundtrippable using JSON). This would require a little bit of documentation and carefully considering the various error cases and how to securely handle them. I'm totally keen to apply a pull request which does this. |
That's great news @NZKoz. |
👍 for @NZKoz plan. [OFF TOPIC] We usually don't take feature requests in the issues tracker. On Thursday, November 14, 2013, Michael Koziarski wrote:
Rafael Mendonça França |
@rafaelfranca understood, thanks for your patience. |
Here is a MVP showing the bare minimal monkey patching required to switch the main cookies from Marshal to JSON: https://gist.github.com/mattetti/7624413 The patch is divided in 3 parts:
Part of the issue is that Finally, we would need a way to set the serializer at the Splice::Application.config.session_store :cookie_store, key: '_splice_session', domain: "splice.com", serializer: JSON Getting a PR ready is quite a lot of work since as @NZKoz mentioned, documentation, upgrade/migration testing are needed. But at the same time, this is for me a major security concern, especially when working in big companies where usually employees have access to the session secret and can easily tamper with the cookie after they leave the company and execute any kind of nasty code server side. |
Actually it would be possible to make a serialiser that will fall back to loading via Marshal, and will always dump as JSON. This could be a solution to migrate all sessions to a JSON serialised format. |
It would still make the cookie content unsafe to load. I personally don't |
I'm aware that it would still be unsafe, however it's a viable upgrade path for the people that don't want to invalidate all their current sessions, but still want to migrate to a safer serialiser. |
Note that you're using the JSON.load/dump API, which is for marshaling Ruby objects. As long as you're unmarshaling Ruby objects, RCE is possible. Changing the format is a red herring and has no bearing on that. Use the JSON.parse/generate API to restrain usage to JSON primitives. |
@jeremy good call, you're absolutely right, fixing that now. |
"The second is to share the session across apps written in a different language.", the application I maintain has this exact use case. In our case, a Grails application handles authentication (using Shiro) but some actions are performed in the Rails app. For simplicity, our client get cookies from both applications. In the Rails side, an authentication request will go through a custom strategy that will forward the cookies to the Grails app and check if it's valid. If so, it will create a Devise valid cookie valid for up to 10 minutes of inactivity. When signing out from Grails, the Rails cookie is deleted as well. This is not ideal, for some reasons like replay attacks targetting the Rails app after logout and other reasons. So, I totally support a cross-language serializer method for supporting cases like this. |
Hi all, I dropped this patch into my application to see how it would handle my existing sessions and immediately ran into JSON::GeneratorError in SessionsController#create, only generation of JSON objects or arrays allowed. I cleared the (now stale) cookies from the browser and the error persisted. This was generated by the following code:
The token is a string and this was not serializable. Wrapping it in an array gets me past the error. This could be a bug in the my code (and this could be a bad approach) but it is common. |
@jeffrafter / @mattetti, if you want to (de)serialize partial JSON (strings, numbers etc) you need to pass >> require 'json'
=> true
>> JSON.generate('hello')
JSON::GeneratorError: only generation of JSON objects or arrays allowed
from /Users/godfrey/.rvm/gems/ruby-2.0.0-p195/gems/json-1.8.1/lib/json/common.rb:223:in `generate'
from /Users/godfrey/.rvm/gems/ruby-2.0.0-p195/gems/json-1.8.1/lib/json/common.rb:223:in `generate'
from (irb):3
from /Users/godfrey/.rvm/rubies/ruby-2.0.0-p195/bin/irb:16:in `<main>'
>> JSON.generate('hello', quirks_mode: true)
=> "\"hello\"" |
@chancancode good point, I didn't know about |
I didn't know such values were invalid: http://www.json.org/. Indeed Chrome doesn't complain about "JSON.stringify('value')". I don't really understand why Ruby's JSON#unparse complains about this by default... |
@chancancode / @mattetti I can confirm that quirks_mode solves the problem. I looked into .to_json as well in thinking about multi_json support that looks to fallback to dump/load. |
👎 on MultiJson, it has been removed from Rails master (see #13109). If anything we should make this go through ActiveSupport::JSON.encode and AS::JSON.decode unless there are provable perf concerns — On Wed, Dec 4, 2013 at 8:04 AM, Jeff Rafter notifications@github.com
|
Actually, another change was needed: create_additions: true. Without this, the quirks_mode generated tokens wouldn't parse. @chancancode I looked at your commit here https://github.com/rails/rails/pull/12207/files and you seemed to do the same. This fixed the last of my problems with signed single token cookies. |
@jeffrafter: don't do that :( You'll need to pass This raises another point that should be considered along with this change. With |
@chancancode when it's easy to change the serializers then using yaml provides a round trip for dates at least:
|
Not symbols though (and for good reason):
By the way, I'm not saying any of these restrictions are bad, I'm just saying they need to be understood properly. |
@mattetti Have you started or are you planning to start that PR? I am thinking about coding this, so just wanted to check status. |
Unfortunately, I haven't started yet. Please feel feel to start
|
I created PR with what I came up with. It needs some more work, but as this is my first commit to rails where I actually add a feature, it would be awesome to hear if this is good direction at this stage. |
@lukesarnacki That PR actually looks really good. +1 |
@Bertg thanks ;) But I already noticed some kind of stupid mistakes ;) It breaks |
As an update: I added test which actually checks if serializer passed in config is used, I fixed test suite, I changed |
Closed by #13692 |
Rails 4 currently allows sessions to be signed and/or encrypted which is great.
ActionPack
relies onEncryptedCookieJar
which itself relies onActiveSupport::MessageEncryptor
Here is the current constructor:
The encryptor can accept a serializer, if a serializer isn't passed, then
Marshal
is used.The serializer is used to load/dump the session content.
I understand that we can't easily change the default serializer for historic reasons, but I would like to be able to use my own serializer (json, messagepack or whatever).
There are a few reasons for that, one mentioned by @tarcieri is security reason.
If the secret is leaked, the attacker can potentially execute ruby code on the server.
The second is to share the session across apps written in a different language.
Changing the serializer would obviously not guarantee that you can shove just whatever you want in the session like you currently can do with
Marshal
. Dumping the session object using a more strict serializer would potentially result in exceptions if the data format isn't supported and that's totally fine, actually I would like that.I'm not asking to change the default, just to have a way to set my own serializer and deal with the consequences of my own choices. In other words, I'd like to be able to have a high level config flag to set the session serializer.
Others before me faced the same problem and monkey patched Rails: https://gist.github.com/jeffyip/4091166
I think an option would be a cleaner and safer alternative.
What do you think?
The text was updated successfully, but these errors were encountered: