Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to securely implement the "Remember me" button in PHP (persistent login)

First some background, I'm still learning PHP and I'm trying to build a CMS (disclaimer: for my own use only).

I'm still testing some things and I've succesfully created an admin login system.

So, right now this is how it works:

  • User logs in, after validating and sanitizing inputs, I check if the user exists and I use PHPs password_verify to compare the password to the hashed one stored in the DB.

  • If the login in is successful, I redirect the admin to a dashboard.php and create a session variable called adminId and I store the user ID in that variable.

Here's my first question:

Can an attacker change the value of the $_SESSION['adminId']? For example, change from 1, to 12 and, therefore, login in as a different admin?

Anyway, I've read this article that introduces multiple exploits an attacker can use.

So, if I'm not wrong, I should use cookies for persistent login right?

Ok so the first thing is to never store the user id in a cookie and use that to check for the log in because an attacker can easily change that right?

Fine, so I could create a random token (with random_bytes and then converted to hex) and pair it to a user ID in a logins table in the database.

So for example, I have this:

token: 2413e99262bfa13d5bf349b7f4c665ae2e79e357,
userId: 2

So, the user logs in, token is created, stored in database with userId. Suppose the user closes the browser. Then he opens it again and all it has is the cookie with the token: 2413e99262bfa13d5bf349b7f4c665ae2e79e357. So automatically, it logs in the user with userId: 2 right?

If he wanted to log in as the user with userId: 10 for example, he would need to know the random token paired to that user.

Fine, but then there's this problem: timing leaks. So they propose a solution using two things, a selector and a validator. Here's when I don't understand anymore, this is what the article says:

What follows is our proposed strategy for handling "remember me" cookies in a web application without leaking any useful information (even timing information) to an attacker, while still being fast and efficient (to prevent denial of service attacks).

Our proposed strategy deviates from the above simple token-based automatic login system in one crucial way: Instead of only storing a random token in a cookie, we store selector:validator.

selector is a unique ID to facilitate database look-ups, while preventing the unavoidable timing information from impacting security. (This is preferable to simply using the database id field, which leaks the number of active users on the application.)

enter image description here

On the database side of things, the validator is not stored wholesale; instead, the SHA-256 hash of validator is stored in the database, while the plaintext is stored (with the selector) in the user's cookie. With this fail-safe in place, if somehow the auth_tokens table is leaked, immediate widespread user impersonation is prevented.

The automatic login algorithm looks something like:

  1. Separate selector from validator.
  2. Grab the row in auth_tokens for the given selector. If none is found, abort.
  3. Hash the validator provided by the user's cookie with SHA-256.
  4. Compare the SHA-256 hash we generated with the hash stored in the database, using hash_equals().
  5. If step 4 passes, associate the current session with the appropriate user ID.

So here's what I don't understand:

1) What should the selector and validator contain?
2) Why is this system secure and how it prevents timing leaks?

Thanks in advance, and sorry for long post, but I really want to understand how this works and how can I implement it.

I know I could use some framework or library but I want to make it from scracth, learn by trial and error!

like image 483
nick Avatar asked Sep 09 '17 05:09

nick


People also ask

How to create PHP login with Remember Me functionality using cookies?

In this tutorials, we will learn how to create PHP Login with Remember me functionality using Cookies. Create a simple PHP Form with username ( text field ), password ( password field ), remember ( checkbox) & Login ( submit) button. PHP Cookies are used to store small amount of information on browser than can be used later for different purposes.

How to preserve the user’s logged in status in PHP?

This form contains a checkbox captioned as ‘Remember Me’ to allow the user to preserve his logged in status. When the user submits the login data, the posted details are received in PHP and validated with the member database. On successful login, if the user selected ‘Remember Me’ then the logged-in status is stored in PHP session and cookies.

How to unset the remembered login state from the PHP session?

In the dashboard screen, it contains the welcome text with the logout link. On clicking the logout link, the remembered login state will be unset from the PHP session and cookies. Import this SQL script to test this example in your local environment.

What is user login with Remember Me?

User login with remember me or login with remember password is a feature of web applications to allow user to save login details to login form to populate same login details when try to login from same page. This is very user friendly feature that help to reduce user attempt to type login details again and again.


1 Answers

Can an attacker change the value of the $_SESSION['adminId']? For example, change from 1, to 12 and, therefore, login in as a different admin?

No. The session data is stored only on the server. The client only has the string which identifies the session.

I should use cookies for persistent login right?

If you're going to have persistent logins, this is usually how it's done.

so the first thing is to never store the user id in a cookie and use that to check for the log in because an attacker can easily change that right?

Correct, you will never want to expose any critical data such as a user id.

1) What should the selector and validator contain?

Each would be a properly generated random string (e.g. using openssl_random_pseudo_bytes). The selector must be unique.

2) Why is this system secure and how it prevents timing leaks?

It adds two security features over generating one basic token and looking that up directly.

First, if your database is leaked to an attacker they can not generate their own remember me cookies and impersonate every user. The validator is only stored in the database as a hashed value. The cookie must contain the unhashed value. Reversing a good hash is extremely time consuming.

Second, comparing a hash only generated on the server avoids timing attacks. If an attacker were to send various remember me cookie values to time their lookup, it wouldn't expose anything useful because the comparison on the server is against a hashed value and not the original.

Generally speaking, if your system's security is that important I would recommend against supporting a remember me feature at all. If you do want to use this feature on a important site, use a library which has already been tested to be secure.

like image 82
Matt S Avatar answered Oct 08 '22 06:10

Matt S