Live data from Hacker News

Logout is broken by default in Ruby on Rails Web applications

maverickblogging.com

21–30 of 59 posts

Re: Logout is broken by default in Ruby on Rails Web applications

#21

Pretty sure this can be fixed with a timestamp in the session data. You can either expire the timestamp by time or by keeping a datetime field on the user and updating the timestamp after a password change. Or you can use a combination of these two. This is not a new issue. It is a well known limitation of the cookie store. I've been working around this with timestamps for years.

Can you share maybe the code you're using to do that?

As well: rotating the secret token every night could probably be used to discard all existing cookies, right? (although this is a bit brute force and will kick out anyone currently using the app).

Re: Logout is broken by default in Ruby on Rails Web applications

#22
post #5

This is a very common problem in a lot of signed cookie based session stores. Some frameworks get it right, some don't. The best remediation is to include an expire timestamp within the content of the signed cookie and to check this on the server - you can't rely on the client deleting the cookie ( never trust the client). The guys at GitHub fixed this particular issue in their rails stack, and submitted a pull reque…

FWIW, I just posted this which contains useful code for CookieStore (not tested):

https://news.ycombinator.com/item?id=6546257

Re: Logout is broken by default in Ruby on Rails Web applications

#23
post #5

This is a very common problem in a lot of signed cookie based session stores. Some frameworks get it right, some don't. The best remediation is to include an expire timestamp within the content of the signed cookie and to check this on the server - you can't rely on the client deleting the cookie ( never trust the client). The guys at GitHub fixed this particular issue in their rails stack, and submitted a pull reque…

The giving up statement[1]:

Giving up. The inheritance and mixins approach in the chained and legacy cookie jar code is absurd beyond my patience.

Someone else is free to run with this code as a start and take the credit.

[1] https://github.com/rails/rails/pull/11168#issuecomment-22353...

Re: Logout is broken by default in Ruby on Rails Web applications

#24
post #5

This is a very common problem in a lot of signed cookie based session stores. Some frameworks get it right, some don't. The best remediation is to include an expire timestamp within the content of the signed cookie and to check this on the server - you can't rely on the client deleting the cookie ( never trust the client). The guys at GitHub fixed this particular issue in their rails stack, and submitted a pull reque…

I like to ensure that the key used to sign the sessions is rotated on a regular basis. On Heroku, for example, there is the Secure Key[0] addon which takes care of this for you.

[0] https://addons.heroku.com/securekey

Re: Logout is broken by default in Ruby on Rails Web applications

#25
This feels less like a framework bug for me than an app bug -- an impressively common app bug, I'll grant you, but an app bug nonetheless. Rails doesn't ship with user management. It's pretty upfront about that, and the docs tell you to roll your own since it is easy, and the community will tell you to use Devise since that will save you time since you'll be doing repetitive work for substantially all apps otherwise.

The typical way beginning Rails developers (including me, on my first Rails apps) would implement logins is stuffing the user ID in session[:user_id] and setting the currently logged in user to that when it is both present and in the DB.

It is true that this approach will make sessions replayable. It will also:

1) Make it impossible to reliably expire session, since the user's browser is not under your control and may treat the expiration date as advisory only.

2) Make it impossible to forcibly expire session, which you'll want to do in event of a user changing or resetting their password, changing their username/email address, etc. (Generic security advice for all web apps, by the way. Otherwise compromise of user accounts, via losing password, XSS, or what have you, is impossible to reverse.)

3) Makes it impossible to implement Sign Me Out Of All Devices, which is a very desirable capability to have for many applications. For example, if you have a more-important-than-cat-videos app, somebody losing their phone should probably not result in their account on your service being irrevocably compromised. You could provide a Dropbox-esque UI to manage their state across multiple devices or, in a pinch, just say "If you hit the log out button on any device, we log you out of all devices."

4) The simplest possible Rails login system is facially non-compliant with a number of security regimes you might be under, including HIPAA among others.

n.b. Switching to ActiveRecordStore doesn't by itself solve anything but #1. You do need app-side logic.

Re: Logout is broken by default in Ruby on Rails Web applications

#28
The session data should always be on the server side usually store on memcached or redis. The cookie should just be an id used as a handle to the session on the server side. The server side data should always be deleted on logout.

Nowadays most services work only on HTTPS. In that case is not possible stealing the cookies observing the traffic but there is always malware able to grab the cookies. A mechanism to invalidate the session should always be available.

If you moving data back and forward on HTTP and you are using the cookie to store the variable in the session, there is always the risk to expose sensitive data stored in the session to the outside world.

Re: Logout is broken by default in Ruby on Rails Web applications

#29
post #25

This feels less like a framework bug for me than an app bug -- an impressively common app bug, I'll grant you, but an app bug nonetheless. Rails doesn't ship with user management. It's pretty upfront about that, and the docs tell you to roll your own since it is easy, and the community will tell you to use Devise since that will save you time since you'll be doing repetitive work for substantially all apps otherwise.…

I actually regard this as a framework bug. Rails has been promoting the Cookie-Storage for at least two major releases. There's a couple of upsides to cookie storage that make it appealing, but the downside is the given lack of control. Some of those points you mention could be tackled even with cookie storage, but not all of them:

2) in the case of a compromise you can change the app secret. That's a pretty big sledgehammer and will log out all users from the app, but it will reliable smash that fly.

1) could be tackled the way gitbub proposed: just include the expiry date in the signed cookie. Discard any cookie that's past expiry.

3) could be tackled by using some sort of per-user cookie secret. That however would require a storage again and then you could as well store the whole session in said storage. Not much to win here.

Re: Logout is broken by default in Ruby on Rails Web applications

#30
post #15

How about simply storing a logout timestamp in the database when a user logs out? Whenever a user logs in again the timestamp field is cleared and as long as that timestamp field is empty the session cookie is accepted, otherwise ignored and the user is forced to log in again. Basically we still get benefits from storing the session data client side (much less db access) and only store minimal data on the server side…

Would that not mean that the cookie could still be re-used by a malicious user who had intercepted it, as long as the real user had subsequently logged in again? I guess it reduces the attack surface (the genuine user must be logged in at the same time as the attacker) but doesn't completely solve the problem.

Yes, I think you are right. Additionally the cookie could have a creation timestamp and in the db the last login time is stored. So when the cookie timestamp is older than the last login the cookie is actually outdated and ignored. But again maybe it's simpler to just use serverside session storage ...
Post reply on HN