Replay attacks with cookie session

1,533 views
Skip to first unread message

S. Robert James

unread,
Mar 21, 2007, 2:43:17 PM3/21/07
to Ruby on Rails: Core
I'm concerned about the possibility of replay attacks with cookie
sessions. This is a standard security issue.

Example:
1. User receives credits, stored in his session
2. User buys something
3. User gets his new, lower credits stored in his session
4. Evil hacker takes his saved cookie from step #1 and pastes it back
in his browser's cookie jar. Now he's gotten his credits back.

This is normally solved using something called nonce - each signing
includes a once only code, and the signer keeps track of all of the
codes, and rejects any message with the code repeated. But that's
very hard to do here, since there may be several app servers
(mongrels).

Of course, we could store the nonce in the DB - but that defeats the
entire purpose!

Brad Ediger

unread,
Mar 21, 2007, 3:19:42 PM3/21/07
to rubyonra...@googlegroups.com

You and I think alike. I was just considering this the other day as
well. The trivial fix is to say "don't store sensitive transient data
in the session". I think that leaves something to be desired, but it
is probably the preferred route unless there is a clean technical
solution.

Jeremy Kemper

unread,
Mar 21, 2007, 3:28:02 PM3/21/07
to rubyonra...@googlegroups.com
On 3/21/07, S. Robert James <srober...@gmail.com> wrote:
> I'm concerned about the possibility of replay attacks with cookie
> sessions. This is a standard security issue.
>
> Example:
> 1. User receives credits, stored in his session
> 2. User buys something
> 3. User gets his new, lower credits stored in his session
> 4. Evil hacker takes his saved cookie from step #1 and pastes it back
> in his browser's cookie jar. Now he's gotten his credits back.

Interesting, I hadn't considered that scenario.


> This is normally solved using something called nonce - each signing
> includes a once only code, and the signer keeps track of all of the
> codes, and rejects any message with the code repeated. But that's
> very hard to do here, since there may be several app servers
> (mongrels).

This sounds like something you could perform at the application level.

jeremy

S. Robert James

unread,
Mar 21, 2007, 4:56:52 PM3/21/07
to Ruby on Rails: Core

On Mar 21, 3:28 pm, "Jeremy Kemper" <jer...@bitsweat.net> wrote:


> On 3/21/07, S. Robert James <srobertja...@gmail.com> wrote:
>
> > I'm concerned about the possibility of replay attacks with cookie
> > sessions. This is a standard security issue.

> Interesting, I hadn't considered that scenario.

IMO, we need to rethink moving to cookie sessions by default, then -
if a core member hadn't thought about, what can we expect from
beginners? Last thing we need is a reputation for being weak in
security.

Before everyone responds: "It will help performance, and good
developers don't store volatile data in the session, anyway!" I'll say
that we've seen lots of companies (who won't be named) sacrifice
security in order to gain out of the box performance or ease of use -
and it comes back to haunt them. Secure by default, and let the
advanced users make it less secure to improve performance - not the
other way around.

>
> > This is normally solved using something called nonce - each signing
> > includes a once only code, and the signer keeps track of all of the
> > codes, and rejects any message with the code repeated.

> This sounds like something you could perform at the application level.
I don't think so - as long as step 2 (in my example) goes to one
Mongrel, and step 4 goes to another, the attack succeeds. I can try
repeatedly with a script until this happens. The only way to protect
is to use a shared backend like the DB or DRB - but then you've lost
the point of cookie sessions.

Jeremy Kemper

unread,
Mar 21, 2007, 5:26:58 PM3/21/07
to rubyonra...@googlegroups.com
On 3/21/07, S. Robert James <srober...@gmail.com> wrote:
> IMO, we need to rethink moving to cookie sessions by default, then -
> if a core member hadn't thought about, what can we expect from
> beginners? Last thing we need is a reputation for being weak in
> security.

I think that's a bit sensational. The cookie store has gone through a
couple of evolutionary steps already and is ready for more, if need
be.


> Before everyone responds: "It will help performance, and good
> developers don't store volatile data in the session, anyway!" I'll say
> that we've seen lots of companies (who won't be named) sacrifice
> security in order to gain out of the box performance or ease of use -
> and it comes back to haunt them. Secure by default, and let the
> advanced users make it less secure to improve performance - not the
> other way around.

Let's see a brainstorm of solutions and other potential vulnerabilities.


> > > This is normally solved using something called nonce - each signing
> > > includes a once only code, and the signer keeps track of all of the
> > > codes, and rejects any message with the code repeated.
>
> > This sounds like something you could perform at the application level.
> I don't think so - as long as step 2 (in my example) goes to one
> Mongrel, and step 4 goes to another, the attack succeeds. I can try
> repeatedly with a script until this happens. The only way to protect
> is to use a shared backend like the DB or DRB - but then you've lost
> the point of cookie sessions.

To some degree. I'm sure there's more to this, though. I'm not a crypto expert.

jeremy

Preston Lee

unread,
Mar 21, 2007, 6:08:22 PM3/21/07
to rubyonra...@googlegroups.com
I'm neither a Rails nor cryptography expert, but the threat of
session hijacking is a very important issue, and due to compliance
requirements such as SOX, sites must think even more seriously about
what is being stored in sessions and cookies, and take reasonable
measures to protect them.. preferably by default.

I'm saddened that many recent Rails books don't seem to cover this
issue. If the problem had more clarity and direction I think that'd
go a long way to easing enterprises into the Rails community.

Preston

Sandofsky

unread,
Mar 21, 2007, 7:28:02 PM3/21/07
to Ruby on Rails: Core
I'm not a crypto person, but what if a version number were embedded
with every write to the cookie session? Of course, check the data
+version against a hash to make sure they didn't tinker with the
version.

On Mar 21, 2:26 pm, "Jeremy Kemper" <jer...@bitsweat.net> wrote:

Brad Ediger

unread,
Mar 21, 2007, 7:45:55 PM3/21/07
to rubyonra...@googlegroups.com
That's essentially what a nonce is, but:

1) Nonce is random and can't easily be guessed
2) It still doesn't solve the multiserver problem: how does one server know what the current version number is when there are 10 Mongrels?

Alexey Verkhovsky

unread,
Mar 22, 2007, 1:16:11 AM3/22/07
to rubyonra...@googlegroups.com
On 3/21/07, Brad Ediger <br...@bradediger.com> wrote:
You and I think alike. I was just considering this the other day as
well. The trivial fix is to say "don't store sensitive transient data
in the session".

Heh... how about a user ID? What if an evil hacker sets it to 1, assuming that the first user is likely to be admin?

Alex

Brad Ediger

unread,
Mar 22, 2007, 1:23:44 AM3/22/07
to rubyonra...@googlegroups.com
He can't, the HMAC wouldn't verify.

Alexey Verkhovsky

unread,
Mar 22, 2007, 1:56:30 AM3/22/07
to rubyonra...@googlegroups.com
On 3/21/07, Brad Ediger <br...@bradediger.com> wrote:
Heh... how about a user ID? What if an evil hacker sets it to 1, assuming that the first user is likely to be admin?

 

He can't, the HMAC wouldn't verify.

Ah, that's right. So the only possible attack vector here is copying the entire cookie, including HMAC?

OK, how about making this option available, but not default? And documenting explicitly that if you switch to this option, you should be extremely cautious about putting what you called "sensitive transient data" in the session? This looks like a good compromise, because people with a clue would still use it (for both maintainability and performance benefits) while people without a clue will have to figure it out, and hopefully read the warning in the docs.

Personally, I'd much rather deal with beginners having "Rails performance sucks" pains early on (because of file-based sessions), rather than discovering that "Rails security is totally screwed" a year after production.

Alex

Manfred Stienstra

unread,
Mar 22, 2007, 3:26:35 AM3/22/07
to rubyonra...@googlegroups.com
On Mar 21, 2007, at 11:08 PM, Preston Lee wrote:

> I'm neither a Rails nor cryptography expert, but the threat of
> session hijacking is a very important issue

It's an important issue when you're trying to have a secure session.
When you're just using the session for some flash variables I don't
see the point in using an overly secure session system.

I think we should document the various session stores very well and
tell people what to use in which circumstances.

Developers aren't small children, we don't have to make their
decisions for them.

Manfred

Thijs van der Vossen

unread,
Mar 22, 2007, 4:35:19 AM3/22/07
to rubyonra...@googlegroups.com

--
Fingertips - http://www.fngtps.com

Phone: +31 (0)6 24204845
Skype: tvandervossen

MSN Messenger: th...@fngtps.com
iChat/AOL: t.vande...@mac.com
Jabber IM: th...@jabber.org

Thijs van der Vossen

unread,
Mar 22, 2007, 4:44:41 AM3/22/07
to rubyonra...@googlegroups.com
On Mar 21, 2007, at 19:43, S. Robert James wrote:
> I'm concerned about the possibility of replay attacks with cookie
> sessions. This is a standard security issue.
>
> Example:
> 1. User receives credits, stored in his session
> 2. User buys something
> 3. User gets his new, lower credits stored in his session

Your example scenario is unrealistic. If you really think it's a good
idea to store such important stuff as your user's credit in a session
instead of in your database you probably have bigger issues to worry
about. :)

As long as you only use the session to maintain the id of the
authenticated user and for flash messages there's absolutely nothing
to worry about.

Kind regards,
Thijs

P.S. If you really _do_ think it's a good idea to store your user's
credit in the session, please google for 'share-nothing' and
'database transactions' and do some reading.

Alexey Verkhovsky

unread,
Mar 22, 2007, 9:52:47 AM3/22/07
to rubyonra...@googlegroups.com
On 3/22/07, Thijs van der Vossen <t.vande...@gmail.com> wrote:
As long as you only use the session to maintain the id of the
authenticated user and for flash messages there's absolutely nothing
to worry about.

Sure, but...

Not everybody who develops web apps knows about "do not keep anything interesting in sessions" mantra, or agrees with it. At least a couple of times I had to explain it to people who were not clueless by any standard.

It's actually a rather arcane bit of knowledge, and if you don't have it, you may discover it the hard way, when it's too late.

Which makes session storage in cookies a good option, but perhaps not a good default (?)

Alex

Brad Ediger

unread,
Mar 22, 2007, 10:44:40 AM3/22/07
to rubyonra...@googlegroups.com
For those just tuning in... :-)

This is the crux of the issue... of *course* it's a terrible idea to store sensitive or transient data in the session, but the question is one of API design. Do we want the penalty for ignoring best practices to be compromised security?

I happen to think it's not a huge deal if we document properly. Web developers need to understand all of the abstractions that Rails builds on top of HTTP in order to build a secure web app. It's the same issue as people who throw things like

<input type="hidden" name="order[total_price]" value="1250.00" />

into their online stores. If you don't understand how the Web works, you won't build secure applications, no matter what framework you work within. When PStore was the default, professional developers understood what that meant and what freedoms and limitations it afforded us. Now that CookieStore is the default session store, we are responsible for understanding what that means.

Don't get me wrong; the Rails team has a part to play in this -- documentation. To the extent that we give the impression that the session is  a "big hash in the sky", people will put stupid things in it. 

After writing this and thinking about it, I realize that authentication may be a problem. It makes me slightly uncomfortable to hand the client a token saying, in effect, "I am logged in as Joe User" with no qualifications, signed by the server. And that token never expires on the server side -- you could come back 5 years later and prove your identity. There is no way to selectively expire sessions, e.g. based on time. You can change the secret, but that expires all sessions including current ones. You can send the client a new cookie that invalidates the old one -- but he can always ignore it. He still has the valid authentication cookie from earlier, and it will still work.

I would feel a lot better about it if it incorporated a nonce or some other form of time-variant information. I can't come up with an attack other than the replay attack, but that "I am logged in as Joe User" message seems too general to make me feel completely comfortable about authentication via cookie sessions for the time being.

Brad

S. Robert James

unread,
Mar 22, 2007, 12:15:41 PM3/22/07
to Ruby on Rails: Core

On Mar 22, 10:44 am, Brad Ediger <b...@bradediger.com> wrote:
> This is the crux of the issue... of *course* it's a terrible idea to
> store sensitive or transient data in the session, but the question is
> one of API design. Do we want the penalty for ignoring best practices
> to be compromised security?

It's even more complicated. Defining "sensitive or transient data" is
not at all trivial.

The standard use case for a cookie session is store only flash and
user id. Not sensitive or transient? Okay.

Now, I click "Log Out", and get up from the library's computer, only
to let the person waiting after me to retrieve the old cookie.... That
innocuous user id just became both sensitive and transient.

The point is, answering these questions is hard. Witness the
confusion in this thread alone. DIY cryptosystems are hard:
professionals fail. WEP failed. Does it make sense to push all these
questions onto each new Rails developer's shoulders?

Brad Ediger

unread,
Mar 22, 2007, 12:28:55 PM3/22/07
to rubyonra...@googlegroups.com

And I think that is exactly what it comes to. That's kind of where I
landed with that post when I started considering what user_id really
meant.

As neat as cookie sessions are, I don't think I'm going to use them
to store authentication info anymore. Too many question marks.

Steve Longdo

unread,
Mar 22, 2007, 2:01:51 PM3/22/07
to rubyonra...@googlegroups.com
This problem can be addressed in a lot of ways.  One of the easiest approaches would be to use a filter to process the validity of a cookie.  Have an after_filter that adds a "single-use" token to the cookie after a request and a before_filter that checks for the "single-use" token when a user makes a new request.  That way a replay attack wouldn't work.

Bundling in something like this into Rails makes a lot of sense.  It would be opt in by adding the filters into application.rb and not forced on anyone by default.
--
Thanks,
-Steve
http://www.stevelongdo.com

Brad Ediger

unread,
Mar 22, 2007, 2:16:45 PM3/22/07
to rubyonra...@googlegroups.com
This was discussed earlier in the thread. The problem is that such a nonce would require communication between the backend servers via DRb or the database, which removes any benefit from storing the cookies client-side. You might as well store the whole session in the database or DRb store.

As for the opt-in, if you're the type of user that would know enough about security to opt in to such a plan, you're probably not storing account balances in a client-side cookie. The discussion we are having concerns sensible defaults.

Alexey Verkhovsky

unread,
Mar 22, 2007, 2:27:23 PM3/22/07
to rubyonra...@googlegroups.com
On 3/22/07, Steve Longdo <steve....@gmail.com> wrote:
Have an after_filter that adds a "single-use" token to the cookie after a request and a before_filter that checks for the "single-use" token when a user makes a new request. 

1. I probably misunderstand your point, because I'm about to say something obvious. Requests that belong to the same session are not guaranteed to be sequential in any meaningful way.

2. The check you are talking about would have to check the session against SOMETHING. Something more specific than a single secret. I.e., a piece of server-side data that maps to the session. Which kills the rationale behind session-based cookies, no?

So, it looks like cookie-based sessions would only work for the same scenarios where "Remember my login on this computer" option without an opt out is acceptable. 
 
Alex

Courtenay

unread,
Mar 22, 2007, 2:53:21 PM3/22/07
to rubyonra...@googlegroups.com
On 3/22/07, S. Robert James <srober...@gmail.com> wrote:
> On Mar 22, 10:44 am, Brad Ediger <b...@bradediger.com> wrote:
> Now, I click "Log Out", and get up from the library's computer, only
> to let the person waiting after me to retrieve the old cookie.... That
> innocuous user id just became both sensitive and transient.

You click 'log out' and it deletes the cookie.
This is no different to a normal server-based session.

court3nay

Patrick Ritchie

unread,
Mar 22, 2007, 2:58:40 PM3/22/07
to rubyonra...@googlegroups.com
Actually, if you have the cookie set to expire at the end of the session, simply closing your web browser should delete the cookie.

Cheers!
Patrick

Brad Ediger

unread,
Mar 22, 2007, 3:00:04 PM3/22/07
to rubyonra...@googlegroups.com

Oh, but it is. With a server-based session, I "Log Out" and my
session can be purged from the server, leaving the old session ID
worthless. With cookie sessions, the cookie is still valid to the
server even if deleted from the browser's cookie repo. There is no
way to selectively expire sessions from the server.

Server-side: someone gets my session ID, I log out, they present the
session ID to the server -> worthless.
Client-side: someone gets my session cookie, I log out, they present
the cookie to the server -> impersonation!


Courtenay

unread,
Mar 22, 2007, 3:08:55 PM3/22/07
to rubyonra...@googlegroups.com
On 3/22/07, Brad Ediger <br...@bradediger.com> wrote:
> > The point is, answering these questions is hard. Witness the
> > confusion in this thread alone. DIY cryptosystems are hard:
> > professionals fail. WEP failed. Does it make sense to push all these
> > questions onto each new Rails developer's shoulders?
>
> And I think that is exactly what it comes to. That's kind of where I
> landed with that post when I started considering what user_id really
> meant.
>
> As neat as cookie sessions are, I don't think I'm going to use them
> to store authentication info anymore. Too many question marks.

You're forgetting that:
(a) sessions already use cookies to store the session ID, so any
issues with cookie interception or other attacks apply to all session
storage methods.
(b) you can't change the contents of the cookie or it will fail the HMAC.

If you're overly concerned with "user_id" haxoring, just use a guid
instead of DB id in your User.find

court3nay

Brad Ediger

unread,
Mar 22, 2007, 3:19:27 PM3/22/07
to rubyonra...@googlegroups.com

Umm... did you read the thread? No, I'm not forgetting any of that,
and those are not my points at all.

(a) Cookie sessions are vulnerable to replay attacks, because the
client can present *any* cookie that it has seen to the server, not
just the most recently sent one. On the other hand, server-side
storage methods are not vulnerable because the session ID always
references the latest version of the session.

(b) Of course the HMAC would fail if you change the session. I'm not
talking about changing the session. I never was. What worries me is
this:

1. I log in; I get session cookie A which corresponds to
"user_id=12345" with the HMAC and everything.
2. I log out and my session cookie is "deleted" -- in the sense of
not being presented to the server anymore. It may hang out on disk or
memory.
3. Someone finds the session and presents it to the server. Since it
is signed by the server, it is accepted and that user is logged in.

Suddenly, a token which had no value after logout (a session ID) now
has immense value (session cookie) because possession of it allows
one to impersonate me at any time in the future.


Jeremy Evans

unread,
Mar 22, 2007, 3:21:17 PM3/22/07
to rubyonra...@googlegroups.com
On 3/22/07, Brad Ediger <br...@bradediger.com> wrote:
>

It's possible mitigate the problem somewhat by having an expiration
time put into the session (which cannot be modified by an attacker due
to the HMAC). However, you still won't be able to manually expire
sessions (i.e. log out).

Jeremy

Brad Ediger

unread,
Mar 22, 2007, 3:29:40 PM3/22/07
to rubyonra...@googlegroups.com

This is the best idea I've seen so far, but it still requires
balancing the attack window (as small as possible) against the
maximum allowed time between requests. Given that replay attacks can
be automated, the acceptable values for these numbers may or may not
overlap, depending on the application.

S. Robert James

unread,
Mar 22, 2007, 4:51:21 PM3/22/07
to Ruby on Rails: Core

On Mar 22, 3:08 pm, Courtenay <court3...@gmail.com> wrote:
> You're forgetting that:
> (a) sessions already use cookies to store the session ID, so any
> issues with cookie interception or other attacks apply to all session
> storage methods.

Not true. Example: if, on logout, you update the session in the DB to
state "No User", the cookie is worthless.

> (b) you can't change the contents of the cookie or it will fail the HMAC.

Yes, but you can replay them. See my first post.

> If you're overly concerned with "user_id" haxoring, just use a guid
> instead of DB id in your User.find

Won't help - see earlier posts.

S. Robert James

unread,
Mar 22, 2007, 5:13:54 PM3/22/07
to Ruby on Rails: Core

On Mar 22, 3:21 pm, "Jeremy Evans" <jeremyeva...@gmail.com> wrote:
> It's possible mitigate the problem somewhat by having an expiration
> time put into the session (which cannot be modified by an attacker due
> to the HMAC). However, you still won't be able to manually expire
> sessions (i.e. log out).

This will only help in cases where the attacker wants to steal
someone's identity. But there are other uses of a replay attack -
like the example I initially mentioned - where this won't help at
all. And even in the identity theft case - what's to stop the
attacker from using the computer 5 minutes after I leave?

In general, I'd offer the amount of confusion on this thread as the
best evidence that the average developer shouldn't have to deal with
these issues by default.

Jeremy Kemper

unread,
Mar 22, 2007, 8:27:42 PM3/22/07
to rubyonra...@googlegroups.com
On 3/22/07, Brad Ediger <br...@bradediger.com> wrote:
> This was discussed earlier in the thread. The problem is that such a nonce
> would require communication between the backend servers via DRb or the
> database, which removes any benefit from storing the cookies client-side.
> You might as well store the whole session in the database or DRb store.

Avoiding a single database lookup isn't the purpose of the cookie store.


> As for the opt-in, if you're the type of user that would know enough about
> security to opt in to such a plan, you're probably not storing account
> balances in a client-side cookie. The discussion we are having concerns
> sensible defaults.

This discussion skipped plugging the session replay hole. I understand
your concern, but I think you underestimate the average Rails
developer.

For example: to prevent user_id replay, store a last access timestamp
in session that's updated on login and logout.

jeremy

Daniel N

unread,
Mar 22, 2007, 8:43:35 PM3/22/07
to rubyonra...@googlegroups.com
On 3/23/07, Courtenay <cour...@gmail.com> wrote:


    (b) you can't change the contents of the cookie or it will fail the HMAC.

If you're overly concerned with "user_id" haxoring, just use a guid
instead of DB id in your User.find

court3nay

So does this mean that I can't use the cookie for client side javascript?  If I want to use it to keep track of some client side script, then I can't?   Is that true?

Cheers


Michael Koziarski

unread,
Mar 22, 2007, 8:46:00 PM3/22/07
to rubyonra...@googlegroups.com
> Avoiding a single database lookup isn't the purpose of the cookie store.

It's worth remembering the downsides to our current default.
Deploying to a 'real' production setup with it is a shortcut to a
heart attack. File locking, mongrel deadlocking, NFS churn. All of
those are real problems which hurt developers every day.

That most applications *already* change their session store indicates
that it's not that big a deal. If you're currently doing something
which is incompatible with the assumptions of the cookie store,
switch. I'm still using sql sessions and intend to continue doing so
:).


--
Cheers

Koz

Brad Ediger

unread,
Mar 22, 2007, 8:51:26 PM3/22/07
to rubyonra...@googlegroups.com
On Mar 22, 2007, at 7:27 PM, Jeremy Kemper wrote:

>
> On 3/22/07, Brad Ediger <br...@bradediger.com> wrote:
>> This was discussed earlier in the thread. The problem is that such
>> a nonce
>> would require communication between the backend servers via DRb or
>> the
>> database, which removes any benefit from storing the cookies
>> client-side.
>> You might as well store the whole session in the database or DRb
>> store.
>
> Avoiding a single database lookup isn't the purpose of the cookie
> store.

Sure, but you do remove a lot of the glamour of the cookie store if
it has to be tied to a database for a nonce lookup anyway.

>> As for the opt-in, if you're the type of user that would know
>> enough about
>> security to opt in to such a plan, you're probably not storing
>> account
>> balances in a client-side cookie. The discussion we are having
>> concerns
>> sensible defaults.
>
> This discussion skipped plugging the session replay hole. I understand
> your concern, but I think you underestimate the average Rails
> developer.

I might be over-concerned here, but I'm not talking about the average
Rails developer. I'm talking about the worst ones. I can tell you
that while the average Rails developer I've worked with would
certainly be able to understand this and work around it, I'm not sure
that the worst ones would even understand what the issue was if it
were explained to them.

> For example: to prevent user_id replay, store a last access timestamp
> in session that's updated on login and logout.

If I understand you correctly, you would also keep a copy of the
latest timestamp server-side. I would submit that for many
developers, storing a timestamp for each session on the server is not
much more attractive than just storing the whole session on the server.

be

Brad Ediger

unread,
Mar 22, 2007, 9:02:34 PM3/22/07
to rubyonra...@googlegroups.com
Nope. Cookies are referenced by name. As long as you don't try to use the same name for your session cookie and your client-side JS, you will be fine.

be

Brad Ediger

unread,
Mar 22, 2007, 9:05:06 PM3/22/07
to rubyonra...@googlegroups.com

This is a good point. The CookieStore is a major improvement over
PStore from a functional perspective. We are arguing over things that
are important to discuss, but still very, very small compared to that.

S. Robert James

unread,
Mar 22, 2007, 10:30:28 PM3/22/07
to Ruby on Rails: Core

On Mar 22, 8:27 pm, "Jeremy Kemper" <jer...@bitsweat.net> wrote:
> For example: to prevent user_id replay, store a last access timestamp
> in session that's updated on login and logout.

Store the last access *where*?

In Mongrel? But only one Mongrel can know that without them talking to
each other.
In the DB? So we need to hit the DB each time, only we need to do it
manually?
In a temp file? That's back to the default session store.
In the cookie itself? We haven't solved the problem. If the attacker
fishes out an older cookie - and, believe me, they're still on the
disk - he does a replay attack.

I think this is a fair question: most of the people arguing that
cookie stores are safe have also pointed out that they're not crypto
experts. Or security experts. Which is fine - I'm sure their top
notch developers. Before making something which relies on crypto the
Rails default, doesn't it make sense to have at least _one_ crypto or
security consultant review it? Perhaps Schneier will take a look...

SRJ, over-and-out

Michael Koziarski

unread,
Mar 22, 2007, 11:42:23 PM3/22/07
to rubyonra...@googlegroups.com
> I think this is a fair question: most of the people arguing that
> cookie stores are safe have also pointed out that they're not crypto
> experts. Or security experts. Which is fine - I'm sure their top
> notch developers. Before making something which relies on crypto the
> Rails default, doesn't it make sense to have at least _one_ crypto or
> security consultant review it? Perhaps Schneier will take a look...

If you'd like to coordinate this, I'd definitely be glad to hear from
them. As it stands I think your complaint boils down to the lack of
server-side invalidation of a session. Most everything else flows
from that. I'm not sure that there's a shared nothing way to take
care of that, but the crypto experts would know for sure.

Please do investigate having someone conduct a review.

--
Cheers

Koz

Luca Mearelli

unread,
Mar 23, 2007, 4:28:18 AM3/23/07
to rubyonra...@googlegroups.com
Michael Koziarski wrote:
> That most applications *already* change their session store indicates
> that it's not that big a deal.

My feeling (this is what I did) is that this happens because they *got
bitten* by the default session store problems, the effects are visible
(mainly the performance issues).

> If you're currently doing something
> which is incompatible with the assumptions of the cookie store,
> switch.

this could be solved by clearly documenting this assumptions (and
perhaps giving suggestions)

> I'm still using sql sessions and intend to continue doing so
> :).

hmm... how about defaulting to these (at least for the production
environment)?

Luca
--

Web: http://spazidigitali.com - http://thetyper.com
Email mailto://luca.m...@gmail.com
Skype callto://l.mearelli
--

Sandofsky

unread,
Mar 23, 2007, 4:30:36 AM3/23/07
to Ruby on Rails: Core
Pulling two IDs (session id + nonce) from the DB is better than
pulling 80k that could go in cookies. Why not include nonce in the
default, and if the developer wants the blazing speed (and
corresponding dangers), they can disable it?

Brad Ediger

unread,
Mar 23, 2007, 10:39:22 AM3/23/07
to rubyonra...@googlegroups.com
On Mar 23, 2007, at 3:30 AM, Sandofsky wrote:

>
> Pulling two IDs (session id + nonce) from the DB is better than
> pulling 80k that could go in cookies. Why not include nonce in the
> default, and if the developer wants the blazing speed (and
> corresponding dangers), they can disable it?

80k cannot go in cookies. On most platforms the limit is 4k. The
CookieStore raises an error if you try to store too much.

And it's a difference between grabbing the data from the DB to
deserialize it and grabbing it from a cookie to deserialize it. The
main driver isn't performance -- it's not having to keep all of those
sessions around on the web server.

Jeremy Kemper

unread,
Mar 23, 2007, 11:31:35 AM3/23/07
to rubyonra...@googlegroups.com
On 3/22/07, Brad Ediger <br...@bradediger.com> wrote:
> On Mar 22, 2007, at 7:27 PM, Jeremy Kemper wrote:
> > Avoiding a single database lookup isn't the purpose of the cookie
> > store.
>
> Sure, but you do remove a lot of the glamour of the cookie store if
> it has to be tied to a database for a nonce lookup anyway.

Smudge her mascara a little; she's still sexy in the morning.

I already User.find(session[:user_id]) per request, so perhaps my
expectations are different from yours.


> > This discussion skipped plugging the session replay hole. I understand
> > your concern, but I think you underestimate the average Rails
> > developer.
>
> I might be over-concerned here, but I'm not talking about the average
> Rails developer. I'm talking about the worst ones. I can tell you
> that while the average Rails developer I've worked with would
> certainly be able to understand this and work around it, I'm not sure
> that the worst ones would even understand what the issue was if it
> were explained to them.

I don't think you're over-concerned. However, attempts to find a
solution are not argument that session replay isn't a problem.


> > For example: to prevent user_id replay, store a last access timestamp
> > in session that's updated on login and logout.
>
> If I understand you correctly, you would also keep a copy of the
> latest timestamp server-side. I would submit that for many
> developers, storing a timestamp for each session on the server is not
> much more attractive than just storing the whole session on the server.

Let's talk about practical fixes rather than whether we should write
it off entirely.

An application-level solution to user_id replay:

Per request:
@current_user =
User.find_by_id_and_last_seen_at(session[:user_id],
session[:last_seen_at])

On login:
@current_user.update_attribute :last_seen_at, Time.now
session[:user_id] = @current_user.id
session[:last_seen_at] = @current_user.last_seen_at

On logout:
@current_user.update_attribute :last_seen_at, Time.now
reset_session

This requires one additional database query on logout to invalidate
future reuse of that session and no additional per-request queries.

Anyone care to try a generic, automatic nonce and benchmark the results?

jeremy

Jeremy Evans

unread,
Mar 23, 2007, 12:45:14 PM3/23/07
to rubyonra...@googlegroups.com
On 3/23/07, Jeremy Kemper <jer...@bitsweat.net> wrote:
> Let's talk about practical fixes rather than whether we should write
> it off entirely.
>
> An application-level solution to user_id replay:
>
> Per request:
> @current_user =
> User.find_by_id_and_last_seen_at(session[:user_id],
> session[:last_seen_at])
>
> On login:
> @current_user.update_attribute :last_seen_at, Time.now
> session[:user_id] = @current_user.id
> session[:last_seen_at] = @current_user.last_seen_at
>
> On logout:
> @current_user.update_attribute :last_seen_at, Time.now
> reset_session
>
> This requires one additional database query on logout to invalidate
> future reuse of that session and no additional per-request queries.

This assumes you are doing a query per request anyway, and basically
piggy backing on it for the security. If your application is already
doing a query for the current user for every request, sure, there's
almost no additional cost. However, if your application isn't doing a
query per request, you have to add one to get the security, which
makes the cost the same as using the database for session storage.

IMO, this is not a problem that the application developer should need
to deal with manually, any more than application developers should
handle database transactions manually. If cookie based session
storage is going to remain the default:

1) There should be a configurable timeout set automatically, with a
reasonable default (to partially mitigate the replay issue)
2) It should be documented that replay attacks are still possible
3) Advice on creating application specific solutions such as the one
you mentioned should be included in the documentation

Note that timeouts provide only slight additional security, as they
only protect against attackers who get access to a session cookie
after it has already expired. If an attacker gets access to any
session cookie before it expires, they can keep that session open
indefinitely.

Jeremy

Brad Ediger

unread,
Mar 23, 2007, 12:52:04 PM3/23/07
to rubyonra...@googlegroups.com
Good points. I worked up a quick plugin that uses DRb to store the nonce, and I'm doing some benchmarks on it now. I don't have time for anything fancy, but we can at least get in the ballpark.

Or, to put it in Zed's terms, we'll just run it 100 times each way and compare the numbers. :-)

<ducks>

Brad Ediger

unread,
Mar 23, 2007, 1:29:54 PM3/23/07
to rubyonra...@googlegroups.com

To use, install the plugin and start up the DRb server from the DRb session store (action_controller/session/drb_server.rb). 

The DRb server keeps a hash mapping session HMACs to the latest nonce used with the session. The nonce is verified along with the HMAC on unmarshal. That way, old sessions are invalidated because the HMAC of the session must be presented with the latest nonce stored in the DRb backend.

Right now, the code issues a new nonce on each update; it should probably check first to see if the data has been updated, but it doesn't right now.

Very simple benchmarking shows a 10-15% impact on reqs/sec with this plugin. I would guess that most of that comes from the nonce generation (I use Rails's CGI::Session.generate_unique_id, which has to create an MD5 hash for each session). I don't really have the time to look further, however. I only tested with a single Mongrel. Does anyone care to do some performance studies on this?

Brad

On Mar 23, 2007, at 11:52 AM, Brad Ediger wrote:

Good points. I worked up a quick plugin that uses DRb to store the nonce, and I'm doing some benchmarks on it now. I don't have time for anything fancy, but we can at least get in the ballpark.

<snip>

Jeremy Kemper

unread,
Mar 23, 2007, 2:18:09 PM3/23/07
to rubyonra...@googlegroups.com
On 3/23/07, Jeremy Evans <jeremy...@gmail.com> wrote:
> On 3/23/07, Jeremy Kemper <jer...@bitsweat.net> wrote:
> > Let's talk about practical fixes rather than whether we should write
> > it off entirely.

...


> > This requires one additional database query on logout to invalidate
> > future reuse of that session and no additional per-request queries.
>
> This assumes you are doing a query per request anyway, and basically
> piggy backing on it for the security. If your application is already
> doing a query for the current user for every request, sure, there's
> almost no additional cost. However, if your application isn't doing a
> query per request, you have to add one to get the security, which
> makes the cost the same as using the database for session storage.

That assumption is stated at the beginning of the example:


> > An application-level solution to user_id replay:

You reason that touching the database "makes the cost the same as
using the database for session storage" which is likely wrong and
certainly unsubstantiated.

Criticism is great and welcome, everyone, but let's add some
creativity and code to the mix, please.


> IMO, this is not a problem that the application developer should need
> to deal with manually, any more than application developers should
> handle database transactions manually. If cookie based session
> storage is going to remain the default:

We all agree on this. We're working on it.


> 1) There should be a configurable timeout set automatically, with a
> reasonable default (to partially mitigate the replay issue)
> 2) It should be documented that replay attacks are still possible
> 3) Advice on creating application specific solutions such as the one
> you mentioned should be included in the documentation

Good ideas.


> Note that timeouts provide only slight additional security, as they
> only protect against attackers who get access to a session cookie
> after it has already expired. If an attacker gets access to any
> session cookie before it expires, they can keep that session open
> indefinitely.

Not in the scenario above: the legitimate user logging out invalidates
the attacker's session, which is the same behavior as a server-side
session.

jeremy

Sandofsky

unread,
Mar 23, 2007, 2:35:54 PM3/23/07
to Ruby on Rails: Core
> 80k cannot go in cookies. On most platforms the limit is 4k. The
> CookieStore raises an error if you try to store too much.

http://tools.ietf.org/html/rfc2109

"at least 4096 bytes per cookie ... at least 20 cookies per unique
host or domain name"

Is there something in today's cookie implementation that prevents
someone from doing 20 cookies at 4k each?

Brad Ediger

unread,
Mar 23, 2007, 2:43:19 PM3/23/07
to rubyonra...@googlegroups.com

I defer to my original statement:

>> The CookieStore raises an error if you try to store too much.

There is a hard-coded 4k limitation in the store, and the store will
only use one cookie per session.

S. Robert James

unread,
Mar 23, 2007, 5:47:02 PM3/23/07
to Ruby on Rails: Core
On Mar 22, 11:42 pm, "Michael Koziarski" <mich...@koziarski.com>
wrote:

> If you'd like to coordinate this, I'd definitely be glad to hear from
> them....I'm not sure that there's a shared nothing way to take

> care of that, but the crypto experts would know for sure.
>
> Please do investigate having someone conduct a review.

Will do - I'll speak to some of my contacts and see if they're willing
to do a short review, pro bono.

> I'm not sure that there's a shared nothing way to take
> care of that

Exactly. Basically, you can mathematically prove that the only way to
avoid replay attacks is with some type of trusted store. Which of
course needs to be shared.

@Brad - Great work on setting up some code for benchmarking. I
haven't reviewed your code, but doing nonces correctly gets into some
sticky synchronization and concurrency. Basically, the system needs
to make sure that:

* The nonces used by all of the Mongrels are kept track of (eg one
counter per Mongrel)

* No Mongrel uses the same nonce (eg prefix the nonce with the
Mongrel's pid)

* That the issuing a nonce, restoring a session, and then invalidating
the nonce are all done in the correct order. This can get very
tricky:

Specifically, we need to make sure that once the session has been
modified, its nonce is invalidated immediately. At the same time, we
can't invalidate it before a new session has been assigned, or those
requests will be incorrectly rejected. This gets very, very tricky
when you're dealing with multiple overlapping requests: invalidate too
soon, and you've broken pipelining. Invalidate too late, and you're
subject to replay attacks. Like I said, crypto is hard: amateur
cryptosystems are usually broken with relish.

@Jeremy - you're raising a good issue. I think it would be beneficial
to define exactly what the goals of cookie sessions are. Performance?
Less administrative setup? Simplicity (I think that's been lost
already)? Not having to store dormant sessions? I'll add that, IMO,
an attraction to coolness and clever code is *not* a goal worth
pursuing.

S. Robert James

unread,
Mar 23, 2007, 6:00:34 PM3/23/07
to Ruby on Rails: Core

On Mar 22, 11:42 pm, "Michael Koziarski" <mich...@koziarski.com>
wrote:

> If you'd like to coordinate this, I'd definitely be glad to hear from
> them. As it stands I think your complaint boils down to the lack of
> server-side invalidation of a session. Most everything else flows
> from that. I'm not sure that there's a shared nothing way to take
> care of that, but the crypto experts would know for sure.
>
> Please do investigate having someone conduct a review.

To get started, here's a good link on the concept of replay attacks
and nonces:
http://www.openidenabled.com/openid/replay-attack-prevention

And here's a nonce implementation by Sam Ruby (not a crypto expert by
any means, but a smart Ruby dev for sure - the implementation is in
Python, though):
http://www.intertwingly.net/blog/1585.html

Brad Ediger

unread,
Mar 23, 2007, 6:03:06 PM3/23/07
to rubyonra...@googlegroups.com
On Mar 23, 2007, at 4:47 PM, S. Robert James wrote:

> @Brad - Great work on setting up some code for benchmarking. I
> haven't reviewed your code, but doing nonces correctly gets into some
> sticky synchronization and concurrency. Basically, the system needs
> to make sure that:
>
> * The nonces used by all of the Mongrels are kept track of (eg one
> counter per Mongrel)
>
> * No Mongrel uses the same nonce (eg prefix the nonce with the
> Mongrel's pid)
>
> * That the issuing a nonce, restoring a session, and then invalidating
> the nonce are all done in the correct order. This can get very
> tricky

Don't use that code. I had the wrong approach about this, and just
saw my mistake. We will need to rethink the approach, probably after
review from an expert. I'll be thinking about this in the meantime,
and I'll try to at least think a little next time before I start coding.

Sam Bravard

unread,
Mar 24, 2007, 12:55:06 PM3/24/07
to Ruby on Rails: Core

This is a basic distributed systems problem. There is no way to do a
secure shared nothing approach on the client side without creating
server side tracking/coordination overhead. I know cookie sessions
look simple and appealing at first but we're trading scalable
simplicity (db store), for complexity. For security and reliability
some sort of token (timestamps or nonces) would have to be coordinated
across all server instances and it needs to be perfectly coordinated
to work effectively.

http://www.cs.vu.nl/~ast/books/ds1/toc.html (chapters 5, 6, and 8 are
good backgrounders)

The downsides of the cookie approach:

*) It causes more lookups/coordination overhead on the server side.
You still need a db or distributed transaction coordinator lookup
(each server in a cluster needs to know some sort of cluster protocol
for token or timestamp management), so we're not saving a db lookup
and have to maintain coordinator and recovery logic.
*) It puts state unencrypted in a client device we have no control
over (open to attack, reduces the usefulness of the store if we can't
put anything we want in there and feel safe about it)
*) It puts state in an unreliable device (browsers crash - especially
firefox with a few add-ons ;) that would require recovery logic

What is so broken that requires all of this messy overhead and
limitations?

In my mind there needs to be an overwhelming pain to justify the cost
and I can't see/feel the pain to justify this effort and wasted time
on the core list.

SamB


On Mar 23, 11:18 am, "Jeremy Kemper" <jer...@bitsweat.net> wrote:

Wayne E. Seguin

unread,
Mar 24, 2007, 5:42:10 PM3/24/07
to rubyonra...@googlegroups.com
I have a question on this discussion.

Would using Ajax requests throw a wrench into the works?

The example I'm thinking of is:

1. Request 1 hits the server invalidating the nonce for the session,
and runs for a bit

2. Request 2 comes in and gets rejected, hence the request fails and
something expected to happen doesn't

3. Request 1 completes and a new session cookie is set so that the
next action completes successfully.

Thanks,

~Wayne

Thijs van der Vossen

unread,
Mar 25, 2007, 2:01:10 AM3/25/07
to rubyonra...@googlegroups.com
On Mar 23, 2007, at 1:51, Brad Ediger wrote:
> I might be over-concerned here, but I'm not talking about the average
> Rails developer. I'm talking about the worst ones. I can tell you
> that while the average Rails developer I've worked with would
> certainly be able to understand this and work around it, I'm not sure
> that the worst ones would even understand what the issue was if it
> were explained to them.

So you actually want to start designing the framework for its _worst_
users? :)

Kind regards,
Thijs

--
Fingertips - http://www.fngtps.com

Phone: +31 (0)6 24204845
Skype: tvandervossen

MSN Messenger: th...@fngtps.com
iChat/AOL: t.vande...@mac.com
Jabber IM: th...@jabber.org

Brad Ediger

unread,
Mar 25, 2007, 8:41:58 AM3/25/07
to rubyonra...@googlegroups.com
On Mar 25, 2007, at 1:01 AM, Thijs van der Vossen wrote:

>
> On Mar 23, 2007, at 1:51, Brad Ediger wrote:
>> I might be over-concerned here, but I'm not talking about the average
>> Rails developer. I'm talking about the worst ones. I can tell you
>> that while the average Rails developer I've worked with would
>> certainly be able to understand this and work around it, I'm not sure
>> that the worst ones would even understand what the issue was if it
>> were explained to them.
>
> So you actually want to start designing the framework for its _worst_
> users? :)

From a security standpoint, absolutely. Certainly there is some
responsibility on the developer's part to learn how the web works,
but the framework should be as forgiving as possible to new users.

--be

Message has been deleted

S. Robert James

unread,
Mar 25, 2007, 5:12:22 PM3/25/07
to Ruby on Rails: Core
On Mar 25, 12:52 pm, "Andreas Schwarz" <goo...@andreas-s.net> wrote:

> On 24 Mrz., 18:55, "Sam Bravard" <sam.brav...@gmail.com> wrote:
>
> > What is so broken that requires all of this messy overhead and limitations?
>
> I agree with your view. Storing session data in cookies is a bad idea,
> even if correctly implemented with a nonce. But the current
> implementation in Rails is just outright dangerous and should be
> removed.

Here, here!

I did some more work over the weekend and have come up with some other
serious problems, which I want to discuss after I've looked into them
more.

Koz asked me to try to get a professional review done. To do this, I
need two things (preferably
from core):

1. A short but precise spec on how the cookie sessions work. The
people doing the review may never have seen a line of Ruby in their
lives. The spec should be specific and technical, just not assume
knowledge of Ruby. It should also be brief, if we want anyone to go
over it pro bono.

2. A sample app, with src code and full configuration. It can be
simple or even trivial, but it should show how the cookie session is
designed to be deployed. But it has to follow the type of use that
would be recommended - nothing like "in real life, of course, we'd do
it in a more secure way". The configuration and the like are just as
important as the app src.

Brad Ediger

unread,
Mar 25, 2007, 6:10:17 PM3/25/07
to rubyonra...@googlegroups.com
On Mar 25, 2007, at 4:12 PM, S. Robert James wrote:

> Koz asked me to try to get a professional review done. To do this, I
> need two things (preferably
> from core):
>
> 1. A short but precise spec on how the cookie sessions work. The
> people doing the review may never have seen a line of Ruby in their
> lives. The spec should be specific and technical, just not assume
> knowledge of Ruby. It should also be brief, if we want anyone to go
> over it pro bono.

I would be willing to draft a spec if the core team is too busy. We
could always run it by them for editing / approval.

be

Neil Wilson

unread,
Mar 26, 2007, 2:27:16 PM3/26/07
to Ruby on Rails: Core
Perhaps that is your problem. You haven't modelled the login session
properly in Rails.

There seems to be an assumption that 'session' handles all this
automatically, when in reality it is nothing more than a fancy hash.

A login session exists at a point in time for a particular period of
time. It should expire. It is related to a particular user ID (and
possibly a browser/IP sequence) and a particular set of transaction
sequences. You don't get that with 'session' - you have to model it
properly. If you haven't modelled the functionality, then you can't
expect to use it.

I suspect the name 'session' is the problem. It's an overloaded
concept with a load of built-in expectations. However
'semi_persistent_hash' isn't anywhere as easy to type.

NeilW

On Mar 22, 3:44 pm, Brad Ediger <b...@bradediger.com> wrote:
> I can't come up with an
> attack other than the replay attack, but that "I am logged in as Joe
> User" message seems too general to make me feel completely
> comfortable about authentication via cookie sessions for the time being.

Neil Wilson

unread,
Mar 26, 2007, 2:35:35 PM3/26/07
to Ruby on Rails: Core
The 'standard' use is incorrect. I don't believe it has ever been put
forward as 'best practice' by any serious modeller. All I've seen it
in is in simplified tutorials. Are you sure it isn't a case of truth
by repeated assertion?

You shouldn't be storing ID references to the User model in the
session hash; you should be storing ID references to the
AuthenticatedSessions model.

That way when you click 'LogOut' the relevant AuthenticatedSession
object is deleted from the database, and then it doesn't matter one
jot what the next persion does with the cookie.

If something doesn't fit, then look to the model. You've probably
missed a relationship that should be a first class model object.

On Mar 22, 5:15 pm, "S. Robert James" <srobertja...@gmail.com> wrote:
> On Mar 22, 10:44 am, Brad Ediger <b...@bradediger.com> wrote:
>
> > This is the crux of the issue... of *course* it's a terrible idea to
> > store sensitive or transient data in the session, but the question is
> > one of API design. Do we want the penalty for ignoring best practices
> > to be compromised security?
>
> It's even more complicated. Defining "sensitive or transient data" is
> not at all trivial.
>
> The standard use case for a cookie session is store only flash and
> user id. Not sensitive or transient? Okay.
>
> Now, I click "Log Out", and get up from the library's computer, only
> to let the person waiting after me to retrieve the old cookie.... That
> innocuous user id just became both sensitive and transient.
>
> The point is, answering these questions is hard. Witness the
> confusion in this thread alone. DIY cryptosystems are hard:
> professionals fail. WEP failed. Does it make sense to push all these
> questions onto each new Rails developer's shoulders?

Brad Ediger

unread,
Mar 26, 2007, 2:40:31 PM3/26/07
to rubyonra...@googlegroups.com
How, exactly, would you model the login session so as to be immune to
replay attacks with shared-nothing on the server side?

session[:user_id] is perfectly safe with a server-side session. It is
not with a client-side session.

User session expiration has almost nothing to do with this
discussion. Expiring user sessions doesn't prevent sessions from
being replayed during the validity period. And there's no way to
expire user sessions with only a client cookie. We're looking first
for a general solution.

I do have a bigger problem with your statement that "If you haven't
modelled the functionality, then you can't expect to use it." It is
the job of the framework to give developers functionality that they
don't have to model. Otherwise Rails would just punt and say "Here's
how you set and read a cookie. If you want to use sessions, model
them yourself."

Brad Ediger

unread,
Mar 26, 2007, 2:45:55 PM3/26/07
to rubyonra...@googlegroups.com
I'm not sure you understand the distinction here.

We had server-side sessions before. We still do. They accomplish everything you are describing, without requiring every developer to implement an AuthenticatedSession object himself. Look into ActiveRecordStore in action_controller/session/active_record_store.rb.

This discussion is about the recent move to sessions stored in a cookie, and how to secure such sessions. I would suggest you go to Google Groups and read this thread from the beginning to get the background.

Neil Wilson

unread,
Mar 27, 2007, 11:24:13 AM3/27/07
to Ruby on Rails: Core
I understand the distinction very well. I would suggest that you have
ascribed more capability to 'session' than the semantics of that
facility allow.

What I'm saying is that now you have client side session data, you
have exposed the limited semantics of 'session' and there is an issue
that was simply masked by the server side stores.

Rails has never offered authenticated anything. That's why there is no
standard login mechanism.

Why not switch to session side stores and mask the issue, or implement
an AuthenticatedSession that does what you want it to do (and release
it as a plugin if you so desire). Complex cookie encryption might be
an interesting technical puzzle, but is it really required by default?

It's a question again of where the framework ends and the application
begins. I don't believe that there is justification for foisting
complex default encryption mechanisms on the framework when the
'problem' is that you are using the wrong model. Just use a server
side session store.

Now I may be wrong about 'session'. Perhaps it is a much more complex
object than it appears. Perhaps it should be. That is not for me to
decide.

NeilW

> >> questions onto each new Rails developer's shoulders?- Hide quoted text -
>
> - Show quoted text -

Neil Wilson

unread,
Mar 27, 2007, 11:36:07 AM3/27/07
to Ruby on Rails: Core

On Mar 26, 7:40 pm, Brad Ediger <b...@bradediger.com> wrote:
> How, exactly, would you model the login session so as to be immune to
> replay attacks with shared-nothing on the server side?

Use a server side session store, not a client side one.


> I do have a bigger problem with your statement that "If you haven't
> modelled the functionality, then you can't expect to use it." It is
> the job of the framework to give developers functionality that they
> don't have to model. Otherwise Rails would just punt and say "Here's
> how you set and read a cookie. If you want to use sessions, model
> them yourself."

Why not go the whole hog and provide us with a default fifteen level
login system with access control lists?

The issue is where the framework ends and the application begins. A
Rails app that just uses the flash and a setting to determine whether
to show the welcome page doesn't need nonces and anti-replay devices.

Perhaps the first job is to step back a little and ask how much you
*really* should stuff into session. What is the job of that little
semi-persistent-hash?

NeilW

Brad Ediger

unread,
Mar 27, 2007, 11:59:19 AM3/27/07
to rubyonra...@googlegroups.com
Hi-
Thanks for the levelheaded response. I'm sorry if I was a little
inflammatory before. Occupational hazard. :-)

Comments follow.

On Mar 27, 2007, at 10:24 AM, Neil Wilson wrote:

> I understand the distinction very well. I would suggest that you have
> ascribed more capability to 'session' than the semantics of that
> facility allow.
>
> What I'm saying is that now you have client side session data, you
> have exposed the limited semantics of 'session' and there is an issue
> that was simply masked by the server side stores.

(snip)


> Why not switch to session side stores and mask the issue, or implement
> an AuthenticatedSession that does what you want it to do (and release
> it as a plugin if you so desire). Complex cookie encryption might be
> an interesting technical puzzle, but is it really required by default?

I think we're on the same page here, but maybe coming at it from
opposite directions. I think the session abstraction, as exposed by
the server-side stores, worked fine. I don't think it was masking
anything -- I wouldn't say that every aspect of an application's
semantics needs to be captured explicitly in the model. As an
abstraction, the server-side stores provided everything that
developers needed, even considering sensitive and volatile data
(i.e., authentication information).

The problem comes when you try to change the abstraction. Storing
sensitive data with an untrusted client is always tricky -- it's the
reason that ATM cards are fundamentally more secure than any
anonymous e-cash system. "Complex cookie encryption" covers a lot of
ground... the HMAC will definitely be required if you want any
integrity at all, and some sort of nonce is (provably) required if
replayed sessions can hurt you in any way.

However, I think that it is too much to ask of new developers to
implement the whole AuthenticatedSession thing (along with the
requisite security analysis) themselves. As Robert James pointed out
in this thread, security analysis is really tricky -- there are N
ways to get it wrong and 1 way to get it right. And forcing
developers to consider security at this level isn't too friendly, IMO.

I believe that CookieStore should be either (1) secure against replay
attacks by default, or (2) not the default session store. Anything
else is asking too much of non-security-aware developers.

--be

Alexey Verkhovsky

unread,
Mar 27, 2007, 12:05:56 PM3/27/07
to rubyonra...@googlegroups.com
+1 to:

Jonathan Weiss

unread,
Mar 27, 2007, 3:53:43 PM3/27/07
to rubyonra...@googlegroups.com

> I believe that CookieStore should be either (1) secure against replay
> attacks by default, or (2) not the default session store. Anything
> else is asking too much of non-security-aware developers.

+ 1

Jonathan


--
Jonathan Weiss
http://blog.innerewut.de

S. Robert James

unread,
Mar 27, 2007, 10:46:13 PM3/27/07
to Ruby on Rails: Core
There are some other very serious security issues with cookie store as
it stands now.

As I said earlier, I'm waiting for a spec and sample app before
working on a full review. If those never happen, I'll eventually post
the sketches that I already have. But I think the community would be
happier with a material "this is how the app can be compromised" over
"theoretically, depending on the implementation, this might be the
problem." Anyway, if I don't here back on those things, I'll post my
notes from conversation - if I do, I'll try to get a full review done.

On Mar 27, 12:05 pm, "Alexey Verkhovsky" <alexey.verkhov...@gmail.com>
wrote:

Pete Yandell

unread,
Mar 28, 2007, 12:42:07 AM3/28/07
to rubyonra...@googlegroups.com

On 23/03/2007, at 6:19 AM, Brad Ediger wrote:

> (a) Cookie sessions are vulnerable to replay attacks, because the
> client can present *any* cookie that it has seen to the server, not
> just the most recently sent one. On the other hand, server-side
> storage methods are not vulnerable because the session ID always
> references the latest version of the session.

+1 for hitting the nail on the head.

Brad Ediger

unread,
Mar 28, 2007, 9:48:39 PM3/28/07
to rubyonra...@googlegroups.com

On Mar 27, 2007, at 9:46 PM, S. Robert James wrote:
As I said earlier, I'm waiting for a spec and sample app before
working on a full review.  

I went ahead and wrote up a spec. Here's my first crack at it. 

Everyone: Please feel free to make suggestions / corrections.

--------

-- Rails Sessions

The Rails web application framework provides storage for sessions, which are small pieces of data that persist across a stream, or "session," of requests by the same user.

In this document, "user" means a person that makes requests via HTTP to a server. "Client" refers to a software program (usually a web browser) acting on the user's behalf.

A session may be used to store any type of data, but it is most commonly used for the following information:

* A user ID number, which identifies the currently logged-in user
* A "return to" URL, which indicates the location the user should be sent to after logging in (used when an unauthenticated user tries to access a restricted page)
* "Flash" information, or short notification and error messages concerning the status of the user's most recent request

Clearly, the key security requirement is data integrity. The client is not trusted, and must not be allowed to modify the session, create sessions, or assume another client's session. All session modification is performed by the server, which is trusted.

In some cases, the client may not be allowed to read the session (e.g., account numbers, third-party passwords), but this use of the session is strongly discouraged. However, it is desired that Rails be forgiving of session misuse, in that such misuse should not cause hidden security vulnerabilities where at all possible.

The only action that the client is allowed to directly perform on the session is abandonment. At any time, the client may make a request that does not include the session identifier. The server treats this as a new session. Rails applications are written so that abandonment of a session at any time does not cause problems.

Rails aims for a "shared-nothing" style of scalability, in which there may be many application servers running Rails. All shared state is held in either the database or some custom-engineered repository (such as memcached). A load balancer is placed in front of the application servers to distribute requests. This way, any server can handle any incoming requests. A stream of requests comprising a session may hit several servers over the course of the session.

-- Server-Side Session Storage

Until February 2007, all storage for sessions took place on the server. There were several backends that stored sessions on the filesystem, in a database, or in memory. This provided data integrity (since these resources can only be modified by the server) and confidentiality (as the sessions were only trafficked between the application server or servers). Confidentiality may have been a detail of implementation rather than a design goal in this instance.

Under server-based storage, the session is indexed by a session ID, which is an MD5 hash of:

* POSIX time (seconds since epoch)
* Microseconds part of current time
* A pseudorandom number in the interval [0,1), converted to a string
* The application server's process ID
* The string 'foobar'

All of this randomness serves to mitigate session hijacking attacks, as session IDs cannot be easily guessed. The client is given the generated session ID in an HTTP cookie. Sessions can expire either when the browser is closed or after a fixed period of time (between 15 minutes and months to years, depending on the application); this is controlled by the expiration time on the cookie.

-- Client-Side Session Storage

In February 2006, a new session storage method was introduced and is now the default for edge (trunk) Rails. The release branches have not yet switched to this method. This method, the CookieStore, stores the entire session in Base64 encoding in a cookie.

The CookieStore provides no confidentiality, but integrity is assured by signing the cookie with an HMAC. SHA-1 is the default. The server verifies the HMAC every time the cookie is deserialized. The HMAC is keyed off of a user-supplied secret. For new applications, Rails creates a secret when the application is generated. The secret is generated from the session ID algorithm described above, where 'foobar' is replaced with the application's name.

There is a 4 KB limit to the total Base64-encoded data, including the HMAC. This limit reflects the standard architectural limitation imposed on HTTP cookies. There is no graceful recovery from an oversized session -- it is an error to attempt to store more than 4 KB of data in a session under the CookieStore.

The advantages of the CookieStore are twofold: (1) The cookies are transmitted as part of the standard HTTP request/response cycle, so there is little session-lookup overhead. The roundtrip to the database server or shared memory store is eliminated. (2) The server does not need to keep track of open sessions. This mitigates a potential denial-of-service vulnerability where a client could open many sessions and exhaust a server's inodes.

There are some disadvantages, though. All sessions are considered equal to the server -- it is a consequence of not having to keep track of every session in progress. Without some shared state (such as flags on a user account in the database), the server must either honor all sessions or none of them. There is no way to selectively delete or expire sessions. Session expiration can be achieved without shared state if an expiration time is included in the cookie, but this requires sending a new cookie with each request (cookies are normally only sent when session data changes).

A more serious problem with the CookieStore is the possibility of replay attacks. Since the cookie consists only of the session data signed with an HMAC, a valid session can be saved and replayed later; it will always be valid at the framework level unless the secret is changed. The application programmer can introduce time-variant information to invalidate old sessions (as described above), but from the framework's perspective, if the server signed it at some point, it is a valid session.

It has been suggested that a nonce be incorporated into the cookie to prevent replay attacks. This presents several logistical problems, though none of them is insurmountable. First, the nonce will necessarily change with each request and therefore the cookie must be regenerated, re-signed, and retransmitted to the client with each request. Secondly, and most importantly, the nonces must be synchronized among the application servers. This necessitates hitting the database or another shared store on every request for a nonce lookup and update.

-----------


--be

Thijs van der Vossen

unread,
Mar 29, 2007, 3:02:02 AM3/29/07
to rubyonra...@googlegroups.com
On Mar 29, 2007, at 3:48, Brad Ediger wrote:
> On Mar 27, 2007, at 9:46 PM, S. Robert James wrote:
>> As I said earlier, I'm waiting for a spec and sample app before
>> working on a full review.
>
> I went ahead and wrote up a spec. Here's my first crack at it.
>
> Everyone: Please feel free to make suggestions / corrections.

I'm probably missing something here, but what exactly is your goal
for this?

Sam Bravard

unread,
Mar 29, 2007, 4:22:54 AM3/29/07
to Ruby on Rails: Core
Someone on Caboose want to chime in and bring this thread to rest?

Short summary: someone made a well meaning change to sessions that is
broken and creates more pain than it solves.
Desired result: rollback the patch.

DHH, what say you?

On Mar 29, 12:02 am, Thijs van der Vossen <t.vandervos...@gmail.com>
wrote:

Isak Hansen

unread,
Mar 29, 2007, 4:28:32 AM3/29/07
to rubyonra...@googlegroups.com
On 3/21/07, S. Robert James <srober...@gmail.com> wrote:
>
> I'm concerned about the possibility of replay attacks with cookie
> sessions. This is a standard security issue.
>

Just adding my $0.02:

I like the shared-nothing cookie store as an option, for
performance/scalability reasons. Just document the vulnerability to
replay attacks and maybe add a timestamp to limit how long the cookie
remains valid.

The nonce thing adds a lot of complexity, and if you need to hit
shared storage anyway there's just no point. As far as I'm concerned,
updating a nounce or the actual session data has similar overhead.


I'd prefer a db backed session store replacing the current default.
Ideally it would be automatically created, indexed and purged of stale
data.


Isak

Tomas Jogin

unread,
Mar 29, 2007, 5:37:42 AM3/29/07
to rubyonra...@googlegroups.com
How about just NOT changing the default setting to this less secure
option? Problem solved.

Thijs van der Vossen

unread,
Mar 29, 2007, 7:04:44 AM3/29/07
to rubyonra...@googlegroups.com
On Mar 29, 2007, at 10:22, Sam Bravard wrote:
> Short summary: someone made a well meaning change to sessions that is
> broken and creates more pain than it solves.
> Desired result: rollback the patch.
>
> DHH, what say you?

The 'someone' was [1] bitsweat aka Jeremy Kemper who works for
37signals where David Heinemeier Hansson is a partner. I suspect
they've talked about this... ;)

Kind regards,
Thijs

[1] http://dev.rubyonrails.org/changeset/6184

Steve Longdo

unread,
Mar 29, 2007, 9:26:22 AM3/29/07
to rubyonra...@googlegroups.com
Have any metrics been gathered on the "performance/scalability" of the new method or is it imaginary premature optimization?

On 3/29/07, Isak Hansen <isak....@gmail.com> wrote:

Brad Ediger

unread,
Mar 29, 2007, 10:51:04 AM3/29/07
to rubyonra...@googlegroups.com
On Mar 29, 2007, at 2:02 AM, Thijs van der Vossen wrote:

>
> On Mar 29, 2007, at 3:48, Brad Ediger wrote:
>> On Mar 27, 2007, at 9:46 PM, S. Robert James wrote:
>>> As I said earlier, I'm waiting for a spec and sample app before
>>> working on a full review.
>>
>> I went ahead and wrote up a spec. Here's my first crack at it.
>>
>> Everyone: Please feel free to make suggestions / corrections.
>
> I'm probably missing something here, but what exactly is your goal
> for this?

Koz asked for a security review, Robert James said he might be able
to get one, so I wrote a summary of what has been said / done so far.
I was trying to be neutral but detailed, so that's why it might seem
bland.

--be

Obie Fernandez

unread,
Mar 29, 2007, 10:56:22 AM3/29/07
to rubyonra...@googlegroups.com
On 3/29/07, Tomas Jogin <tom...@gmail.com> wrote:
>
> How about just NOT changing the default setting to this less secure
> option? Problem solved.

+ 1 It sounds like the decision to make cookie store the default was
premature, at best.

By the way, just because this 'feature' is in EdgeRails does not mean
it will make it to a *stable* release, which makes some of the
hand-wringing on periphery of this thread seem a little premature
also.

Jeremy Kemper

unread,
Mar 29, 2007, 3:35:27 PM3/29/07
to rubyonra...@googlegroups.com
On 3/29/07, Obie Fernandez <obiefe...@gmail.com> wrote:
> On 3/29/07, Tomas Jogin <tom...@gmail.com> wrote:
> > How about just NOT changing the default setting to this less secure
> > option? Problem solved.
>
> + 1 It sounds like the decision to make cookie store the default was
> premature, at best.

Planting the seed here led to quick ripening and plenty of pesticide.

> By the way, just because this 'feature' is in EdgeRails does not mean
> it will make it to a *stable* release, which makes some of the
> hand-wringing on periphery of this thread seem a little premature
> also.

Thanks for the fish, all.

jeremy

Thijs van der Vossen

unread,
Mar 29, 2007, 3:43:13 PM3/29/07
to rubyonra...@googlegroups.com
On Mar 29, 2007, at 21:35, Jeremy Kemper wrote:
> On 3/29/07, Obie Fernandez <obiefe...@gmail.com> wrote:
>> On 3/29/07, Tomas Jogin <tom...@gmail.com> wrote:
>>> How about just NOT changing the default setting to this less secure
>>> option? Problem solved.
>>
>> + 1 It sounds like the decision to make cookie store the default was
>> premature, at best.
>
> Planting the seed here led to quick ripening and plenty of pesticide.

Ok, that _is_ really funny. ;)

Kind regards,
Thijs

Brad Ediger

unread,
Mar 29, 2007, 6:09:57 PM3/29/07
to rubyonra...@googlegroups.com
On Mar 29, 2007, at 2:43 PM, Thijs van der Vossen wrote:

> On Mar 29, 2007, at 21:35, Jeremy Kemper wrote:
>> On 3/29/07, Obie Fernandez <obiefe...@gmail.com> wrote:
>>> On 3/29/07, Tomas Jogin <tom...@gmail.com> wrote:
>>>> How about just NOT changing the default setting to this less secure
>>>> option? Problem solved.
>>>
>>> + 1 It sounds like the decision to make cookie store the default
>>> was
>>> premature, at best.
>>
>> Planting the seed here led to quick ripening and plenty of pesticide.
>
> Ok, that _is_ really funny. ;)

I think he's trying for two quotes on project.ioni.st this week. :-)

John Wilger

unread,
Apr 1, 2007, 1:04:51 PM4/1/07
to Ruby on Rails: Core
On Mar 29, 12:35 pm, "Jeremy Kemper" <jer...@bitsweat.net> wrote:
> Planting the seed here led to quick ripening and plenty of pesticide.
<snip>

> Thanks for the fish, all.

So, does that mean this will likely be taken out? If so, I would vote
that it at least be provided as an option if not the default. It's
certainly useful for developers who understand the security concerns
and still feel that it would be an appropriate method of session
storage for their application.

--
Regards,

John Wilger

Reply all
Reply to author
Forward
0 new messages