0

This system is for a personal file upload and sharing web application made with PHP.

When a user logs into the application, it has the option to "stay logged in" after closing and reopening their browser, just like most other web applications. What this actually does is that it sets an HTTP cookie, named auth, with an expiration of 90 days on the client browser that contains a string in the following format: UserIdentifier:SeriesNumber:Token where : is the delimiter. The same data is also persisted in the database table user_auths, but the token will be hashed before it is.

The UserIdentifier is the user identifier of the user that opted to stay logged in, the SeriesNumber is a generated random number between 0 and 2147483647 (inclusive) and the Token a generated random 60 character string of alphabetic, numerical and symbolic characters. An example value would be: 1:902449381:j7j]fP%CxIzcKSg/'wG]XzJd.OsX8"K0FlY')xXQz.5.Q]+KJnXi<>p/t7nz

Every time a user visits the application and is not found in the HTTP session I will:

  1. Try to find the auth cookie on the client browser. If it's found, I check if the value of it contains two : delimiters (checking for the right format), if the correct amount of delimiters is not found I delete the cookie of the client browser and the user is not authenticated.

  2. If above test is passed, I will use the user identifier to search in the db table if the user of the given identifier has any rows in the table (meaning that the user has opted to "stay logged in" on one or more browsers). If the user identifier is not found in the table, I delete the cookie of the client browser and the user is not authenticated.

  3. If the above test is passed, I'll now use both the user identifier and series number to check for a matching row in the db table. If found, I verify the cleartext token from the cookie with the hashed token from the corresponding matching row. If not found or the token is not verified, I assume that either a cookie theft has occurred OR the cookie value has been manipulated. I invalidate / delete ALL the authentication persistence data of this user so that it won't "stay logged in" anymore on ANY browser it opted for, and is not authenticated.

  4. If the cookie has passed the above test, it means that the cookie and its data was valid and the user is considered authenticated. I regenerate the session identifier and put the user in the session. I generate a new token, hash and update it in the corresponding table row and issue the user browser a new cookie auth with the same user identifier, series number and expiration date but with the new token (cleartext version).

This all is processed per browser on each request. For every browser the process is identical. A user can opt to "stay logged in" on multiple browsers it wants to and will also have the option to invalidate all the persisted logins of their account.

To finish it off, I have a script that checks the db table every N minutes for rows older then 90 days and deletes them to keep the table clean and invalidate users persistent logins after the expiration time.

  • 1
    I'm not entirely clear on step 3. If the cookie has been stolen by an attacker and is being subsequently used by that attacker, how are detecting that, if at all? – Xander Sep 23 '14 at 3:47
  • @Xander The attacker will be able to successfully use the cookie until the victim revisits the website. Since the token is updated upon successful authentication, the attacker would now have the updated token but the victim would still have the cookie with the old token. The system will see this and invalidate all persisted logins of the user account, including that of the attacker. – Kid Diamond Sep 23 '14 at 3:50
1

Some things to consider:

  • make sure you set the domain/path of the cookie so that only your domain (and no sub-domains can read it)
  • You seem to be using HTTP rather than HTTPS. This makes your cookie subject to eavesdropping. Consider using a HTTPS session and a cookie using the secure attribute.
  • 90 days is a long time to hold such a session open. The longer the validity period of the cookie the greater the risk of theft.
  • By leaving the user effectively logged in you are exposing them to a Cross-Site Request Forgery

This thread from Stack Exchange might also be useful

  • The last bullet above is really important - is always directing the user to a landing page after applying the 'remember me' cookie sufficient protection? Obviously doesn't provie any protection within the session though implying that CSRF tokens are still required. – symcbean Sep 23 '14 at 12:42
  • How am I exposing them to a potential CSRF attack? I require a valid CSRF token on every form submission, even if the user is authenticated or not. And it's regenerated after it's been successfully used. – Kid Diamond Sep 23 '14 at 14:21
  • CSRF is an attack that tricks the user into submitting a request to your page when they think they are doing something else. Since it is coming from the real user, and is heading to you, it will include your security token. You will process the request and send a new token to the user. – DodgyG33za Oct 1 '14 at 4:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.