« Rails 1.2.6 security update | Main | restful_authentication login security »
Tuesday
Nov202007

Rails 2.0 cookies (updated)

Rails 2.0 will include a new default session storage, the CookieStore (source source). What it does is store the clear text "marshalled" session object in a cookie which will be stored on the client side. Here is an example of a new cookie value:

BAh7BzoMdXNlcl9pZGkKIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpG%250
AbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--be9c1e802c6cf126c722c680
02ccbd5684a96dd9

Well, it is actually not clear text, but Base64 encoding. So everything you store in the session object can be seen by the client. This is especially bad if you store secrets in the session, because you thought they will be safe there. But it should be safe for saving an id, for example. Update: You can implement an EncryptedCookieStore very easily, so no one can see the information. But again, the password for this encryption has to be strong.
When the cookie travels back from the client to the application, the session data will be "unmarshalled" and made available by means of the session method (e.g. session[:user_id]).

The second part of the cookie (after the --) is a hash (HMAC-SHA1 by default), calculated of the session object along with the secret server side password. On the server side the session value will be checked against this hash, so no one can tamper with it...unless the attacker knows the password (secret) which is in your environment.rb:

  config.action_controller.session = {
    :session_key => '_cookies2_session',
    :secret      => 'secret-secret'  }

You already know what may happen: the user is able to locally brute-force the secret as he has the clear text and the hash of it (Update: whether or not this will be successful depends on the strength of the secret. A sufficiently long secret is safe.). A weak secret is a short one, or one included in a word list (there are some with 40 million entries). You can try to brute-force your secret with John the Ripper which is very fast (I checked over 105 million passwords in less than half an hour). Update: This means the secret should be a strong password (over 40 characters, no words from dictionaries). The latest Rails release forces you to use a secret with at least 30 characters, and it generates a sufficiently long secret by default.

Corey Benninger presented my book and the most dangerous attack methods for Rails at the OWASP AppSec conference in San Jose. And he wrote a nice Ruby script to crack a Rails cookie (with a too short secret!) here and here.

Update: Replay attacks might be another security issue with client-side cookies. If you store state (is_admin, points, money, amount_to_pay, whatever) in a session, it may be replayed. That means an attacker can resend the state in the cookie and thus possibly reduce a price, get more points or become an admin (if the cookie is from someone else who is an admin). Solutions for this are welcome. In any case, it is not a good idea to save such information in sessions, no matter whether it's a client- or server-side session store.

There are different cookie stores, depending on your needs. If you use CookieStore, please set a very long secret (over 40 characters, no words from dictionaries), preferably some sort of hash as the Rails generator for new project proposes. Also, keep in mind that an attacker might use the knowledge from the cookie somewhere else in your application.

PrintView Printer Friendly Version

EmailEmail Article to Friend

References (80)

References allow you to track sources for this article, as well as articles that were written in response to this article.
  • Response
    Response: Carmine Paith
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: journals.Fotki.com
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Anne-Lise
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Yukinobu
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Abbas
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Www.Imonplugin.Com
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Ailene
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: indong21.com
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: www.ccil-ccdi.ca
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: lillie.nl
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Www.Zeitnews.Org
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Starbound
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: glorystarbet
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Andropenis Review
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: anti wrinkle serum
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Zen Body Reviews
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: testo xl Review
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Zen Body Reviews
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: winrar
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: KW here
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Read Alot more
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Read Alot more
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Rebelmouse.Com
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: telecharger avast
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: http://Scribd.com
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: Cellan Review
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: zespół weselny
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Response: mcaf.ee
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)
  • Response
    Ruby on Rails Security Project - Journal - Rails 2.0 cookies (updated)

Reader Comments (21)

How about proposing that this CookieStore gets fixed before the mainstream starts to use Rails 2?
No use starting off on the wrong foot.

November 20, 2007 | Unregistered CommenterJustin Akehurst

If your paranoid about someone cracking your secret key, you can change hash algorithm to SHA512 and change secret keys for each users.

# Store a secret key per user and employ a stronger message digest.
config.action_controller.session = {
:digest => 'SHA512',
:secret => Proc.new { User.current.secret_key }
}

You could also override read_cookie and write_cookie in (http://svn.rubyonrails.org/rails/trunk/actionpack/lib/action_controller/session/cookie_store.rb) so they are encrypted however you want.

Maybe someone can create an EncryptedCookieStore plugin?

November 20, 2007 | Unregistered CommenterJosh Peek

One solution to this problem is not to depend on the developer to think up or generate a password. Rails 2.0 allows you to write "initializer" snippets that automatically load when placed in config/initializer. It would be almost trivially easy to write such a snippet that loads the secret key from an configuration file, and if one does not exist, automatically generate it. Such a setup would not depend on saving the secret key into the version control system, and can be refreshed every time the app gets deployed using Capistrano. Though it would (should) invalidate all the current user sessions once redeployed.

Under this setup, you definitely don't want to serialize objects into the session.

Ho-Sheng Hsiao
Isshen, LLC

November 20, 2007 | Unregistered CommenterHo-Sheng Hsiao

Justin, those were my exact thoughts!

Is someone from the Rails Core team reading this?

November 20, 2007 | Unregistered CommenterAndre P.

@Justin: CookieStore has its right to exist, but only for application where security of sessions doesn't matter (a personal web site where you store your favorite color in a session). CookieStore makes it faster to load the data. But it should NOT be made a default for all Rails apps!

@Josh: changing the algorithm doesn't help, you can still brute-force it. A special secret for each user looks interesting, but if you can crack it, you'll still be able to change the values in the session and hence maybe see data you're not allowed to.

And if you encrypt/decrypt the session you have to make sure it's a good password (again) and the algorithm has to be faster compared to a different session store.

November 20, 2007 | Unregistered CommenterHeiko

[...] Heiko has also added a post about this issue on his RORSecurity.info site. Digg [...]

November 20, 2007 | Unregistered CommenterPhishMe » Owning Rails 2

@Andre: Yes, people from the core team are reading this.

There are two distinct problems outlined here. The potential issues when brute forcing your key are exactly why the default secrets aren't chosen from dictionary words. If you have suggestions for ways to improve the randomness of the value chosen, we're all ears.

As for Signing vs Encrypting the data, we'd happily take patches which implemented encryption, and perhaps even made it the default. There's been talk about this in the past but despite the bluster patches never arrived.

It's worth considering the 1.2 behaviour. The default session store is completely unusable when running on multiple application servers and even on a single application server problems with performance and deadlocks are frequently reported.

So almost every prodution rails application has already switched to active_record_store or some other alternative and their apps will continue to use this alternative store. New applications will have the opportunity to make that one line change if they like. If someone wants to prepare a document describing the relative risks and merits of the different session stores, we can make sure it's referenced prominently in the relevant places.

While I appreciate the information outlined here, the best way to ensure that we address these issues going forward is to raise them on the mailing list.

http://groups.google.com/group/rubyonrails-core

I, and my team mates, look forward to hearing from you.

November 20, 2007 | Unregistered CommenterKoz

This isn't right; heck, it isn't even wrong.

Do you realize this, the cracker you linked, as well as the linked blog entries are based on the first revision of the cookie store? Please remove the rev query parameter (or simply checkout rails trunk) and try again.

I realize this may have been a simple oversight, but you and the linked cracker author have run with it and spread misinformation from a position of authority. I'd appreciate it if you and he would issue corrections.

There are legitimate concerns with the cookie store, but brute force attacks are not one of them.

November 20, 2007 | Unregistered CommenterJeremy Kemper

Correction: the cracker itself does use the HMAC. All the other links are wrong. The concern regarding session secret strength is totally valid. See the discussion on the rails-core list for more.

November 21, 2007 | Unregistered CommenterJeremy Kemper

@Heiko: if User.current.secret_key is a key that is e.g. a 128 character randomly generated string (as it usually is I assume), then Josh's change does help as then a successful brute force attack would be highly unlikely.

November 21, 2007 | Unregistered CommenterLawrence Pit

Why usually?Isn't the programmer free to choose this? But I agree that a long key is a good countermeasure against brute forcing.

November 21, 2007 | Unregistered CommenterHeiko

Wow! That's a big problem! I've seen a lot of posts about all the new features from Rails 2.0... But I think this was the most scary one! :D Thanks for 'warning' us! Now i'll keep my eyes even more open and I'll look for more information about this... If these things really happen, I'd better find a long long long password!!

[]'s

Felipe Giotto

November 21, 2007 | Unregistered CommenterFelipe Giotto

In R0R, is there a way to encrypt and sign state information and render it in the html output? Simialar to ViewState. I just want to avoid cookies for other reasons?

November 21, 2007 | Unregistered CommenterAmy

@Heiko: the programmer is free to choose the key but when you create a Rails 2.0 project it generates a a strong key for you.

November 21, 2007 | Unregistered CommenterPat

I wonder about the motivations for making this the default. Were sessions broken enough to begin with, or is this 'fix' just something to keep the core committers entertained? Brute forcing being made more difficult is a Band-Aid, not a solution. What necessitated this change? Or was it not necessary, only novel?

November 21, 2007 | Unregistered Commentertobyjoe

@Pat: I think Lawrence Pit meant a special key for each user like this:
secret => Proc.new { User.current_user.secret_key }. The generated key for the entire application is strong, yes:
secret => '449fe2e7daee471bffae2fd8dc02313d'

@tobyjoe: CookieStore is faster than PStore (but I've seen no comparison). And it doesn't have to be maintained (no deletion of old sessions). Although I like to keep control over the session's lifetime. You have to include a timestamp in the CookieStore session in order to expire it.

I believe both solutions (client and server side session storage) have its pros and cons, and it is important to understand what they are.

November 21, 2007 | Unregistered CommenterHeiko

Heiko: I understand that there are pros and cons to CookieStore and PStore, and understand what they are. What I don't understand is why the cons of PStore were considered significant enough to change the default behavior to CookieStore.

There are certainly many ways to speed up applications, and all should be considered within the context of a given optimization strategy. If one is concerned with real optimization, they will be removing a lot of ORM use (at least using their own, 'raw' SQL), among other things. Optimization is hard work, and should be reactionary. Introducing CookieStore primarily for optimization can only be reacting to the benchmarking of the simplest possible apps written by the least-experienced developers. With that being the case, those who are most exposed to the risks introduced by client-side sessions are those who are least equipped to secure their apps, least able to understand how to securely use sessions, least capable of auditing and least concerned with optimization.

The introduction of CookieStore is fine - it's cool. It seems like a nice OPTION. Making it the default, though, exposes the very folks who would be least likely to really consider their use of sessions.

Anyone who has ever made a comment against Microsoft for disabling security for the least-capable users out of the box should consider the consistency of their opinions when it comes to something like this.

App defaults should take into account the people most likely to USE the defaults. Claiming that people should be following 'best practices' (a rather dubious term) is to ignore the audience and shirk responsibility in favor of what?

Benchmarks of scaffolded apps in "shoot-outs" and other PR concerns?

November 21, 2007 | Unregistered Commentertobyjoe

Tobyjoe, I see it the same way, yes. We're discussing it here:
http://www.ruby-forum.com/topic/132373
The Core is for a default CookieStore

November 23, 2007 | Unregistered CommenterHeiko

[...] all work with session IDs. It should not be surprising that the introduction of CookieStore has generated a lot of controversy. My first reaction, too, was “OMG what the hell are they [...]

@tobyjoe: I couldn't agree more with your comment about "keeping the committers entertained"! Breaking applications just because they think it's COOL is way uncool. When you have a body of developers and developed applications and documentaion, doing something like this without the strongest of reasons is just plain wrong. Like it or not, the core team has to realize that "backwards-compatibility" is a term they will have to embrace, else Rails will get the reputation of being supported by cowboys who love to code and hate supporting users.

March 17, 2008 | Unregistered CommenterJon

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>