09 February 2016 — Comments
I'm sure you are familiar with those "remember me" checkboxes in login forms. They are a common way to allow a user to keep his/her session in a web application for an extended period of time when he is in a trusted computer.
One could think that it is a small and easy-to-implement feature, but it has indeed a lot of considerations.
I wasn't able to properly implement it in the first projects I worked in, and I'm trying to explain everything I've learned about it in the last years.
In this article I'm not going to show you how to implement a persistent login in one or another programming language, but what are the good practices that should be followed when you implement it in the way you want.
The first thing that one could try is to extend the lifetime of the system that persists the session and identifies the user between requests (usually a cookie).
The problem is that many systems doesn't allow to do that in an isolated way, you are forced to extend the lifetime of all sessions. Also, it is not always easy to change the session lifetime dynamically.
So it's not a good idea, because the user could be accessing your app from a public computer, and his session could be stolen if he forgets to logout.
Because of this, the best way to do it is to have another element (another cookie) that keeps the persistent session and is used to transparently regenerate the regular session when it expires.
How to implement it.
When a user logs in and he has checked the "remember me" field, you will create a cookie with an extended lifetime (for example, 2 weeks).
That cookie will contain a unique token that will identify a user. It should be backed in the database by creating a table that relates the token with a user. It could contain other metadata too, like the client's IP address or a flag that says if the session is still valid.
In consecutive requests, your system will keep checking if an authenticated user exists, but if not, instead of redirecting to a login or returning a 403 status, it should check for the persistent login cookie first.
When that cookie exists, you will find the user it belongs to, and authenticate him. Then, you will invalidate the cookie and the session in the database, and generate a new one that will expire in the same date as the previous one. Finally, the new token should be returned in a new persistent login cookie that will replace the previous one by having the same name.
When the user manually logs out, the persistent login cookie should be dropped too.
Now you have a basic idea on how to implement it, but there are some security considerations to take into account in order to avoid problems in the future.
The first thing that we have to assume is that persistent sessions have their risks. There is no way to implement a completely secure persistent login, but following this instructions the system will be reasonably secure.
- Persistent login will be handled by a cookie in the client and a database in the server (or a similar persistence system).
- Persistent sessions will have an expiration time, for example 2 weeks. During that time, any regular session will be regenerated by the persistent session. Once it has passed, the user will be prompted to provide his credentials when the regular session expires. The expiration time will be set both in the cookie and in the database.
- Persistent login cookies will contain one-time tokens. Once a token has been used it will be invalidated and a new one will be generated.
- In order to protect these tokens from XSS attacks in the site, persistent login cookies should be
HttpOnly, so that they cannot be read from the browser.
- Multiple valid persistent sessions will be allowed.
- When a user logs out, its current persistent session in the database and the persistent login cookie will be invalidated.
- The user should be able to invalidate all the persistent sessions that are still valid.
- Invalid persistent sessions won't be deleted. This way, if the user tries to access with an invalid cookie, he will be notified of a possible stolen cookie, and immediately all the other persistent sessions will be invalidated.
- When the user changes his/her password, all the persistent sessions should be invalidated.
- The token needs to be unique. Just generate some hash including the date and some other field. It doesn't need to be super secure, but make sure to not send critical information to the client (like usernames or passwords).
- And finally, there should be some operations restricted to users whose regular session has been regenerated by a persistent session, like changing a password or performing some kind of payment. In those cases, the user should be prompted for his current password anyway.
Of course, if your system manages critical data, you shouldn't implement persistent login at all. I don't think you have seen it at any bank application.
In any other case, this should be a good way to go.