User authentication is something crucial for every system requiring to have user accounts.
Even (especially) for small websites and businesses, it is critical to always make sure to follow good practices for maximum security.
We're not talking about some hardcore stuff, though, as the OWASP cheatsheet demonstrates.
Bad idea: plain-text storing and unfit mechanisms
Every technique below is a bad idea, resulting in very poor security.
- Storing passwords in plain text, is it really necessary to explain?
- Ciphering passwords, as a password should never be deciphered.
- Using hash mechanisms, as a plain hash algorithm is not made to protect passwords, only to generate a trace of a data (you can throw away md5/sha1).
- Changing the encoding of the password, like base 64. You're not protecting anything, it's basically plaintext here.
- Stacking hash algorithms together, you'll only augment the collision risk and it's still not made for this purpose.
As a developer, you musn't re-develop security mechanisms like password protection. Home-made security gives you no guarantee that your system is to be trusted, unlike provided and well-audited mechanisms, which are "almost" guaranteed safe.
If you had the technical knowledge to do so in a proper and secure way, you would be working in security anyways!
Good idea: Using the provided mechanisms, or using dedicated libraries
As a golden rule, a secure password should never be seen by anyone.
So, how do you actually do that?
Well, you won't store the password, but a derived value, commonly called a hash (note, as this can be confusing, that the value contains more than the plain hash, a lot more is done behind the scenes).
In PHP, the password_hash
function does
the job for you.
You'll store the value generated by the following code in database.
<?php
// Example
$hashed_value_to_store = password_hash($password, PASSWORD_DEFAULT);
As of today, the best algorithm is
PASSWORD_ARGON2ID
.As much as possible, you should follow the following order of preference to choose the algorithm you're gonna use. Note that you can change at any time, it won't break your website.
PASSWORD_ARGON2ID
: The best choice, available from 7.3 onwardsPASSWORD_ARGON2I
: Second best choice, if you must maintain a legacy systemPASSWORD_DEFAULT
: Third best choice, as it'll evolve towards the "current best algorithm" when you'll updatePASSWORD_BCRYPT
: Fourth best choice, to avoid if possible (using the first two instead)
But how do you actually verify that the password the user is providing during login is the one they entered during registering?
Before you answer, no, you won't make another password_hash
and compare
both results.
For that, every library provides a function, and PHP provides the nifty password_verify function.
You can simply use it like the following example.
<?php
// Example, password comes from the login form, and hashed_value comes from the
// saved entry in database
$will_be_true_if_matches = password_verify($password, $hashed_value);