Password storing Published the 2019-06-03 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. [owasp]: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md We're not talking about some hardcore stuff, though, as [the OWASP cheatsheet][owasp] 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). ![Image displaying the password_hash format](/image/hash_format) In PHP, the [`password_hash`](https://www.php.net/password-hash) function does the job for you. You'll store the value generated by the following code in database. ```php 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 onwards > - `PASSWORD_ARGON2I`: Second best choice, if you must maintain a legacy system > - `PASSWORD_DEFAULT`: Third best choice, as it'll evolve towards the "current best algorithm" when you'll update > - `PASSWORD_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](https://www.php.net/manual/en/function.password-verify.php) function. You can simply use it like the following example. ```php