I am reading a great Rails tutorial and came across a passage that I had a question about:
Box 9.2.Sessions and cookies Because
HTTP is a stateless protocol, web
applications requiring user signin
must implement a way to track each
user’s progress from page to page. One
technique for maintaining the user
signin status is to use a traditional
Rails session (via the special session
function) to store a remember token
equal to the user’s id:session[:remember_token] = user.id
This session object makes the user id
available from page to page by storing
it in a cookie that expires upon
browser close. On each page, the
application can simply call
User.find_by_id(session[:remember_token])
to retrieve the user. Because of the
way Rails handles sessions, this
process is secure; if a malicious user
tries to spoof the user id, Rails will
detect a mismatch based on a special
session id generated for each session.
For our application’s design choice,
which involves persistent
sessions—that is, signin status that
lasts even after browser close—storing
the user id is a security hole. As
soon as we break the tie between the
special session id and the stored user
id, a malicious user could sign in as
that user with a remember_token equal
to the user’s id. To fix this flaw, we
generate a unique, secure remember
token for each user based on the
user’s salt and id. Moreover, a
permanent remember token would also
represent a security hole—by
inspecting the browser cookies, a
malicious user could find the token
and then use it to sign in from any
other computer, any time. We solve
this by adding a timestamp to the
token, and reset the token every time
the user signs into the application.
This results in a persistent session
essentially impervious to attack.
I don’t understand what this is saying. I take from it that a unique session ID is created and stored on the client in a cookie. Then when that cookie is sent to the server on a request, the server knows that is the user in question so that the login can be persisted. However, if a malicious user stole the cookie, I don’t understand why they can’t log in from another computer. The author says this is solved by adding a timestamp, but I don’t see how that helps. Further, the author says that the token is reset every time the user signs in, but the whole point is a persistent sign in, so I don’t understand. Please help!
You are correct—a “Remember Me” cookie can be used to steal a login. The issue that they’re trying to resolve are if someone steals your cookie, containing your unique identifier, and hangs on to it—they’d then be able to log into your account at any point in the future.
The usual solution is to invalidate all previous cookies every time that you log into your account using either the username/password or the “Remember Me” cookie, so that a given cookie will allow you to login a single time. The timestamp is how they’re ensuring the uniqueness of each cookie.
If you’re worried about cookies being stolen, a typical solution is to also store the IP address that the request came from, and if the IP address that the cookie is coming from doesn’t match the IP address that the cookie was created from, deny the login and force the user to sign in. This can be inconvenient to users who are behind dynamic proxies, or who carry their laptop to and from work/home/coffee-shop, since their IP address will change all the time.
“Remember Me” is a security hole by design. The goal is to limit how much of a hole it is, and if you’re designing a system that requires absolute security, it’s not a good choice. If convenience is more relevant than security, using timestamps and cookie invalidation limits the potential security issues.
If you’re interested in more information on this topic, the Security Guide section of Rails Guides has an entire section on sessions.