Before Rails 2.0 is coming, I suggest not to make CookieStore the
default session storage. It stores clear-text values on the client-side
and the integrity check hash can be brute-force attacked.
I understand that this has been set due to speed advantages, but I
believe it's better to make better security a default.
I've written a blog post about this
http://www.rorsecurity.info/2007/11/20/rails-20-cookies/
and Corey Benninger presented this at on the OWASP AppSec conference:
http://blog.phishme.com/2007/11/owning-rails-20-cookies-at-owasp/
Heiko.
--
Posted via http://www.ruby-forum.com/.
I posted this on your blog post, but we're probably better off having
the conversation here.
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.
--
Cheers
Koz
The unworkability of the default pstore sessions forces developers to
move to a workable solution using ActiveRecordStore, MemCacheStore,
etc. Cookie session store doesn't break, so it doesn't force a move
to another system. I wonder if documenting risks will be enough to
get people to change when they should.
--
Josh Susser
http://blog.hasmanythrough.com
I had always considered that to be a feature, rather than a defect in
design, which reminds developer not store any sensitive/secret data in
session.
--
Cheers!
- Pratik
http://m.onkey.org
Your analysis is incorrect; you've based it on the first
proof-of-concept code. Please actually checkout the actual Rails
source instead of the examining the first changeset on the web. I
commented on both your blogs. I'd appreciate if you'd correct your
claims.
In my view, the legitimate concerns are:
1) Our explicit choice of transparency with integrity over encryption.
See Pratik's comment: this is intentional and aims to correct a
perception bug. If you're storing secrets in session, odds are you
have a code smell and ought not to. In the rare exceptional case, you
can switch to a server-side session store or write a simple
EncryptedCookieStore subclass.
2) Session replay attack. This is what Corey should have talked about
at OWASP, not the nonexistent brute force attack. A valid session
cookie may be intercepted and replayed by an attacker. The cookie
store is constructed to make solutions to this simple, such as
including a nonce, timestamp, or IP address in the message digest.
Let's put these concerns to bed once and for all:
1) Of those concerned about encoding vs encryption: who's written a
plugin to subclass an EncryptedCookieStore which uses the secret to
do, say, AES encryption with OpenSSL? I implemented this first, before
choosing to go with HMAC, and it's extremely fast and pretty easy to
set up. You can use the same session key, even.
2) Of those concerned about session replay: who's explored the
possibilities available by passing a block to generate the session
key? Let's see plugins implementing per-user keys, nonces, IP binding,
and timestamp-based expiry.
I think talking up the solutions to these concerns is far more
valuable to the community than spreading fear, uncertainty, and doubt
about them. Let's see some code.
Thanks, and best regards,
jeremy
There are a variety of other things which you need to do to remain
secure. Put the h in your <%= etc. If we consider it reasonable to
rely on documentation for this, it seems it should be reasonable to
rely on documentation for the session store.
We can put up a nice page on the rails website outlining the relative
merits and risks of each of the session stores, and link to it from
the generated environment.rb. Seems like a good enough solution for
me, barring any nice refactoring that happens in the meantime.
--
Cheers
Koz
The cookie store option is an unique and interesting solution, however I
feel that it creates an inherent security risk (regardless of if the
data is encoded, encrypted, or has a HMAC). This is what I was hoping to
raise awareness of. I'm sure it will be the perfect solution for some
applications, but where I have a concern is that this will be the
default store. New developers, especially ones coming from other
frameworks, will most likely feel the session is a safe place to store
values that should not be manipulated or viewed. Even if the cookie is
encrypted instead of encoded, it will leave the session open to the
possibility of being cracked and then manipulated.
I think there is a huge advantage to a framework being secure by
default. Defaulting to one of the other session store options would be a
better stance in this regard. Dealing with CSRF and SQL Injections are
security areas where Rails really shines over other frameworks. I'm not
sure new developers would necessary read all the documentation about the
default session store option until after they've had an issue. I think
they would be much more appreciative a more secure solution being the
default.
Thanks,
~Corey
By this standard isn't ssl, encrypted email, and well any kind of
encryption equally fundamentally insecure?
--
Cheers
Koz
Thanks for raising it! The scrutiny is welcome. I do take issue with
your conclusions, however :)
> The cookie store option is an unique and interesting solution, however I
> feel that it creates an inherent security risk (regardless of if the
> data is encoded, encrypted, or has a HMAC). This is what I was hoping to
> raise awareness of. I'm sure it will be the perfect solution for some
> applications, but where I have a concern is that this will be the
> default store. New developers, especially ones coming from other
> frameworks, will most likely feel the session is a safe place to store
> values that should not be manipulated or viewed. Even if the cookie is
> encrypted instead of encoded, it will leave the session open to the
> possibility of being cracked and then manipulated.
Raising awareness of this perception bug is the best answer, in my opinion.
New developers are *better* served by making this the default.
> I think there is a huge advantage to a framework being secure by
> default. Defaulting to one of the other session store options would be a
> better stance in this regard. Dealing with CSRF and SQL Injections are
> security areas where Rails really shines over other frameworks. I'm not
> sure new developers would necessary read all the documentation about the
> default session store option until after they've had an issue. I think
> they would be much more appreciative a more secure solution being the
> default.
Let's not confuse secrecy with security. Session cookies typically
store a user_id and a flash message. We only need to ensure that the
user_id is not changed, and hmac-sha1 provides that beautifully. This
is not by any stretch insecure.
Best,
jeremy
So far there are not many real-world examples, but here are the only
secret keys I found on Google:
to2, ias, random seed, this_can_be_long, some secret phrase,
getyourownsecretkey, with_my_last_breath_i_curse_zoidberg
Some are examples, but chances are cargo-culting will be done.
Especially the first 3 are very dangerous, and there were only 2-3
hashed secrets, the rest are made up of words from dictionaries.
How about an Exception when the secret is to short or not a hash, that
would eliminate the problem?
I know that most session normally store a user_id, but there are a lot
of other sessions (a Google code search shows a lot of examples) and
chances are among these are information the user is not allowed to see.
Another problem raised is session replay: If someone stores state
(is_admin, points,money, whatever) in a session, it can be replayed.
This doesn't happen for server-side cookies. With IP-, timestamp- or
per-user-based solutions the same user can still do the same request
again (maybe in a short timeframe). Hmm, a nonce could do it maybe.
Ok, these are 3, maybe 2.3:) problems with client-side store over
server-side store. If most will switch to another session store, why
make it a default? I know CookieStore works well for a lot of
applications, but w/o fully understanding it, I believe a server-side
solution is more secure.
I'm willing to write up an educational document about the different
options, who's going to eliminate the threat of session replay?
I'm not sure how we could decide if something was or wasn't a hash.
But I've added code that raises if the secret is fewer than 30
characters. Seems like a decent stand-in
> I know that most session normally store a user_id, but there are a lot
> of other sessions (a Google code search shows a lot of examples) and
> chances are among these are information the user is not allowed to see.
This is potentially an issue, but using encryption instead of hashing
would take care of that, right?
> Another problem raised is session replay: If someone stores state
> (is_admin, points,money, whatever) in a session, it can be replayed.
> This doesn't happen for server-side cookies. With IP-, timestamp- or
> per-user-based solutions the same user can still do the same request
> again (maybe in a short timeframe). Hmm, a nonce could do it maybe.
We had a long discussion about replay attacks and a nonce requires
some form of shared storage which removes the reason for a cookie
store. What we could provide is some kind of 'session sanity check'
hook that users can override with their own code. Checking whatever
they want, timestamps, IPs etc.
The threat of a third party replaying a session doesn't worry me too
much. If they have access to the value in that session cookie, then
they also have access to the key used for a server side session store
which is just as dangerous.
The case we need to be careful about is people storing credits etc in
their session and continually restoring the old session once they
spend them all.
> Ok, these are 3, maybe 2.3:) problems with client-side store over
> server-side store. If most will switch to another session store, why
> make it a default? I know CookieStore works well for a lot of
> applications, but w/o fully understanding it, I believe a server-side
> solution is more secure.
>
> I'm willing to write up an educational document about the different
> options, who's going to eliminate the threat of session replay?
> --
> Posted via http://www.ruby-forum.com/.
>
> >
>
--
Cheers
Koz
That's session-store independent, though. You'll get precisely the same
behaviour if you store the inappropriate data in a cookie.
> Sessions already use a cookie, so for many applications it makes sense
> to pop the essentials (user id) into a cookie and otherwise architect
> without sessions. Flash[] remains useful for non-Ajax requests, so
> using the CookieStore for that could be a plus.
Using the cookie store for the flash certainly seems like a win to me -- if
the user plays silly buggers with the values in there, at worst they're only
going to hurt themselves. No need to waste disk space or database CPU
storing and retrieving that stuff all the time.
On the other hand, though, storing things like user ID in the cookie store
is pointless. All you're doing then is using the ActiveRecordStore but with
a different key to retrieve stuff (user ID instead of session ID). If you
store multiple IDs in there (user ID and cart ID, for instance) then your
performance will likely be worse, because you're hitting the database
multiple times to retrieve both of them, rather than just the one chunk of
session data.
You can't possibly get away with *not* loading the models identified by the
IDs in the cookie, even if you only need the ID, because you can't possibly
trust the information that the user is providing -- mangling the user ID to
log in as someone else (if the hash is easily breakable), or even just your
basic common-or-garden-variety replay attack (nonces have the same
server-side storage problem as the data itself, and timestamps give an
easily readable window, while encryption just leaves the attacker to guess
how long the window is, it doesn't close the window). So you need to
validate the ID(s) the user is providing before relying on it/them.
At least with a server-side session store (of whatever variety) session keys
are large enough that guessing them isn't feasible (whereas most everyone
still seems to use sequential integers for user IDs, rather than UUIDs), and
you as the system operator can invalidate a session key just by clearing the
associated data. Once you give data to the client, you lose that much
control of it.
I suppose you might get some performance benefits if you store IDs in the
cookie that are only needed on very few pages, so you don't have to validate
it very often. I'm not guessing that there are many webapps out there that
could benefit from that particular brand of optimisation (although the flash
storage could probably benefit a lot of people -- anyone who runs a purely-
or partially-public Rails site that uses the flash on their public pages).
Anyone want to start a pool on how long it'll be before someone
re-implements ActiveRecordStore on top of CookieStore by just storing a
session_id in the cookie and then loading up an arbitrary chunk of data in
the database based on that value? I'll take 3 months.
Actually, that gives me a bit of an idea -- you could prevent session ID
guessing on a server-side store by making the session ID key:hash, where key
is what we have now and hash is {md5,sha1}(key+secret). Then the server can
validate the session ID with no more than the session ID and the secret.
Doesn't stop replays if you don't expire your sessions, but at least slows
down people guessing.
At any rate, I'm not anti-CookieStore, because I just don't care. I've got
my template Rails project with all my customisations and plugins, and if I
have to change another config option or two, that won't be a big deal for
me. Defaults are always going to piss someone off, so I've given up
worrying about them. At any rate, a lot of the tradeoffs in client-side
stores are similar to server-side stores, just in different clothes, so
there isn't such a big win. I suspect that I might use an encrypted
CookieStore on apps that don't have a database behind them, just to save me
a cron job.
If someone's in a wish-granting mood, being able to store the flash in a
cookie (either a separate one, or as part of the session ID one, isn't a big
deal) while storing the session proper in whatever store you've configured
would be wonderful, and that session ID guessing thing isn't patented or
anything (at least not by me <grin>).
> More on RESTful state transaction models:
>
> "To achieve a RESTful state transaction model, in a nutshell, means
> passing enough data back and forth so that a user can click on any
> feature or function of the application, in any order, and the server
> will (1) know what to do every time without fail, and (2) will not
> 'remember' each client's previous states. This implies that the server
> is 'stateless' with respect to specific client data. The server has a
> state of it's own, and knows it's own transaction state, of course.
> But it is only 'aware' of each client's state when it is contacted by
> the individual clients, and the client notifies the server of it's
> state."
>
> http://www.devchix.com/2007/08/16/restful-thoughts-on-a-web-20-python-project/
I can't manage to read that snippet in any way that isn't either horribly
insecure ("trust what the client is giving you") or is precisely how things
are done now ("client gives me some identifier, I retrieve the current state
of the session from my 'server side state'"). Perhaps the rest (heh) of the
article provides a bit more detail, but reading articles written by RESTful
advocates irritates me for some reason. I like REST, but RESTers bug me.
<grin>
- Matt
> On the other hand, though, storing things like user ID in the cookie
> store
> is pointless. All you're doing then is using the ActiveRecordStore
> but with
> a different key to retrieve stuff (user ID instead of session ID).
> If you
> store multiple IDs in there (user ID and cart ID, for instance) then
> your
> performance will likely be worse, because you're hitting the database
> multiple times to retrieve both of them, rather than just the one
> chunk of
> session data.
The normal usage is: you store the user_id in the cookie and perhaps a
flash. Nothing else. When a request comes you directly load the user.
You trust the ID because there's a mechanism that validates data
integrity.
With the database store you have to hit the database _twice_. One to
load the session given its key, and another one to load the actual
User. Of course you don't store instances in the session, that's a bad
practice. So in terms of database hits cookie storage is much lighter.
In terms of maintenance a win, something less to care about in the
server.
> You can't possibly get away with *not* loading the models identified
> by the
> IDs in the cookie, even if you only need the ID, because you can't
> possibly
> trust the information that the user is providing -- mangling the
> user ID to
> log in as someone else (if the hash is easily breakable),
But it isn't with default settings! That's the whole point of
providing this feature.
-- fxn
If you're *just* storing an ID and the flash, then the only danger is
the rather infeasible one of someone cracking your secret by brute
forcing the hmac.
The additional risk is that because cookie sessions can't be expired,
an attacker with access to your cookie will be able to replay that
login indefinitely. Unlike the server side stores where someone
gaining access to your cookie only has access for as long as it takes
for you to clear out the server side store.
> Without evidence it's just a conspiracy theory.
There are real risks with the cookie store, and it's good to be
discussing them openly. Just because they're not OMFG THE WORLD IS
OVER doesn't mean they're not risks ;)
> On Nov 22, 12:23 am, Xavier Noria <f...@hashref.com> wrote:
> > But it isn't with default settings! That's the whole point of
> > providing this feature.
>
>
> >
>
--
Cheers
Koz
I ran across this site today... looks helpful:
http://www.rorsecurity.info/
- nathan.
On Nov 23, 2007 10:16 PM, Neil Wilson <aldu...@gmail.com> wrote:
>
> I always find with security people that they are good at talking about
> theoretical risks, but poor at providing evidence that the actual risk
> is significant.
>
> Can somebody show a security violation with correctly architectured
> Rails application (ID/Flash session)?
If you're *just* storing an ID and the flash, then the only danger is
the rather infeasible one of someone cracking your secret by brute
forcing the hmac.
The additional risk is that because cookie sessions can't be expired,
an attacker with access to your cookie will be able to replay that
login indefinitely. Unlike the server side stores where someone
gaining access to your cookie only has access for as long as it takes
for you to clear out the server side store.
> Without evidence it's just a conspiracy theory.
There are real risks with the cookie store, and it's good to be
discussing them openly. Just because they're not OMFG THE WORLD IS
OVER doesn't mean they're not risks ;)
> On Nov 22, 12:23 am, Xavier Noria < f...@hashref.com> wrote:
> > But it isn't with default settings! That's the whole point of
> > providing this feature.
>
>
> >
>
--
Cheers
Koz
Absolutely, if you lose the secret, you're in trouble.
--
Cheers
Koz
--
Cheers
Koz
All of these risks are based on the assumption that it's feasible to
brute force the secret. As far as I'm aware it's not. As we've said
before, if someone wants to provide patches to implement public key
encryption instead of HMACs, we'll take them.
--
Cheers
Koz