Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP best practices for user authentication and password security

People also ask

How do I authenticate a user in PHP?

Once the user has filled in a username and a password, the URL containing the PHP script will be called again with the predefined variables PHP_AUTH_USER , PHP_AUTH_PW , and AUTH_TYPE set to the user name, password and authentication type respectively. These predefined variables are found in the $_SERVER array.


OpenID is a method to authenticate users based on their existing accounts on common web services such as Yahoo, Google and Flickr.

Logins to your site are based on a successful login to the remote site.

You do not need to store sensitive user information or use SSL to secure user logins.

A current PHP version of the library can be found here.


Implementing user authentication securely without relying on a framework (or third-party library, such as OpenID) to do it for you is not a trivial undertaking.

At a 10,000 foot overview, you have to decide:

  • Do you have usernames, email addresses, or user IDs as a primary selector?
  • How should you store passwords? PROTIP: password_hash() or scrypt are the way to go.
  • How should you handle "remember me" checkboxes? There are a lot of bad strategies for this on the Internet. Treat every one of them with skepticism, because they might introduce vulnerabilities into your application.
  • How should the application handle users who forget their password?

The information in this answer is relevant and up-to-date as of May 9, 2015 and might be obsoleted by the conclusion of the password hashing competition

Primary Selectors

In general, usernames and email addresses are better than ID numbers.

There should be no security requirement to keep usernames secret, because in practice they will be leaked when someone tries to register anyway.

You can decide whether or not to treat email addresses as a secret. Users generally like not being exposed to spammers, scammers, and trolls.

Password Hashing

You should use password_hash() and password_verify() unless you are sufficiently experienced with writing cryptography libraries to go above and beyond.

Beyond Bcrypt

Sometimes developers like to get creative (e.g. adding a "pepper", which usually means pre-hashing or HMACing passwords with a static key) and go beyond the standard implementations. We ourselves have done this, but very conservatively.

For our internal projects (which have a much higher margin of security than most people's blogs), we wrote a wrapper around this API called PasswordLock that first hashes a password with sha256, then base64 encodes the raw hash output, then passes this base64-encoded hash to password_hash(), and finally encrypts the bcrypt hash with a properly-implemented encryption library.

To reiterate, instead of peppering, we encrypt our password hashes. This gives us more agility in case of a leak (we can decrypt then re-encrypt because we know the key). Additionally, we can run our webserver and database on separate hardware in the same datacenter to mitigate the impact of a SQL injection vulnerability. (In order to start cracking hashes, you need the AES key. You can't get it from the database, even if you escape to the filesystem.)

// Storage:
$stored = \ParagonIE\PasswordLock\PasswordLock::hashAndEncrypt($password, $aesKey);

// Verification:
if (\ParagonIE\PasswordLock\PasswordLock::decryptAndVerify($password, $stored, $aesKey)) {
    // Authenticated!
}

Password Storage with PasswordLock:

  1. hash('sha256', $password, true);
  2. base64_encode($step1);
  3. password_hash($step2, PASSWORD_DEFAULT);
  4. Crypto::encrypt($step3, $secretKey);

Password Verification with PasswordLock:

  1. Crypto::decrypt($ciphertext, $secretKey);
  2. hash('sha256', $password, true);
  3. base64_encode($step2);
  4. password_verify($step3, $step1);

Further Reading

  • Security Issue: Combining Bcrypt With Other Hash Functions
  • password_hash
  • password_verify
  • password_compat (for PHP < 5.5.0)

I use OpenID .

But like stackoverflow I use the Google project openid-selector to do the heavy lifting.
Demo Page here.

The obvious advantages (of OpenID) are.

  • You don't need to be a security expert.
  • Users trust the big sites with their info.
  • You can request things like (nickname etc) but user has to opt in.
  • You don't need to worry about:
    • registration processes
    • lost/forgotten password

A lot of great answers here, but I feel like it's worth saying this--do NOT try to re-invent the wheel in this case! It is extremely easy to screw up user authentication in a wide variety of ways. Unless you really need a custom solution, and have a firm knowledge of security schemes and best practices, you will almost certainly have security flaws.

OpenID is great, or if you're going to roll your own, at least use an established library and follow the documentation!


PHPass is a lightweight, variable cost password hashing library using bcrypt.

Variable cost means that you can later turn up the 'cost' of hashing passwords to seamlessly increase security without having to invalidate your previously hashed user passwords.

The field size used for hash storage is constant even when increasing 'cost' due to increasing not the size of the hash, but the number of iterations required to produce it.