Wachtwoorden opslaan anno 2014
Ik kwam onderlaatst in discussie met een persoon over de beste wijze van het opslaan van wachtwoorden.
Welke voorkeur gaat hier bij jullie uit?
Ik lees over deze functie van PHP zelf; http://nl1.php.net/password_hash, maar hoe veilig zal dit nu precies werken tegenover een SHA1, of MD5, of zelfs een SHA1 + MD5 combinatie?
Of wat zijn de voordelen van password_hash tegenover PBKDF2?
Kortom, wat gebruiken jullie graag en waarom? :)
Welk algoritme wordt gebruik hangt af van de tweede parameter.
Er zijn nu (PHP 5.5) twee mogelijke waarden: PASSWORD_DEFAULT en PASSWORD_BCRYPT.
"PASSWORD_DEFAULT - Use the bcrypt algorithm (default as of PHP 5.5.0). Note that this constant is designed to change over time as new and stronger algorithms are added to PHP. For that reason, the length of the result from using this identifier can change over time. Therefore, it is recommended to store the result in a database column that can expand beyond 60 characters (255 characters would be a good choice)." - de door jou gelinkt pagina
Dat betekend dat als je ooit over gaat op een PHP versie die een ander default algoritme heeft de NIEUWE hashes met dat algoritme gehasht zullen worden.
Gebruikers met oude hashes kunnen nog steeds inloggen omdat password_verify() aan de hash kan zien welk algoritme gebruikt is. Dat betekend dat het wachtwoord met het juiste algoritme gehasht zal worden tijden het inloggen waarna de twee hashes vergeleken worden, als deze overeen komen returned password_verify() true.
Met password_needs_rehash($hash, PASSWORD_DEFAULT) kun je bepalen of een wachtwoord gehasht is met de nieuwste default, als dat niet zo is kun je tijdens (wel pas als je weet dat het wachtwoord en hash bij elkaar horen) het inloggen het wachtwoord opnieuw hashen, de nieuwe hash sla je dan op in de database. Op die manier wordt de beveiliging automatisch verhoogd door alleen over te gaan op een nieuwe PHP versie!
"PASSWORD_BCRYPT - Use the CRYPT_BLOWFISH algorithm to create the hash. This will produce a standard crypt() compatible hash using the "$2y$" identifier. The result will always be a 60 character string, or FALSE on failure." - de door jou gelinkt pagina
Dit zal altijd Bcrypt gebruiken als het algoritme, ook wanneer je over gaat naar een PHP versie die een ander default algoritme heeft.
MD5 is snel, en er is sinds 1996 een fout in het ontwerp bekend.
SHA1 is snel, en er is sinds 2010(?) een fout in het ontwerp bekend.
PBKDF2 is traag (er vanuit gaand dat je een goede cost kiest) en er is geen kwetsbaarheid van bekend.
Bcrypt is traag (er vanuit gaand dat je een goede cost kiest) en er is geen kwetsbaarheid van bekend.
Wanneer is traag zeg heb ik het over enkele honderden miliseconden trager. Enkele honderden miliseconden tijden het inloggen met een correct wachtwoord is niets voor een gebruiker. Enkele honderden miliseconden is enkele honderden miljarden sececonden extra wanneer je een paar miljard mogelijke inputs gaat bruteforcen.
Er zijn zo'n 20 miljard mogelijke combinaties voor 8 tekens lange combinaties waar alleen de 26 letters (klein/groot, kies er één) gebruikt mogen worden.
Traagheid is dus goed!
password_hash is dus geen hashing algoritme, het is wel een een lid van een handige familie van functies speciaal toegevoegd om het developers gemakkelijk te maken om wachtwoorden veilig op te slaan.
Op het moment is wordt het aangeraden om een van de volgende algoritmes te gebruiken: Bcrypt, PBKDF2, Scrypt. (alfabetische volgorde)
De voor- en nadelen van alle drie de algoritme zijn te lezen op de volgende pagina: https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords
PS. als je denkt om in de toekomst over te gaan op SHA3, SHA3 is stukken sneller dan SHA2 en dus niet geschikt voor wachtwoorden. PBKDF2-SHA512 is beter geschikt voor wachtwoorden dan PBKDF2-SHA3.
PPS. Mozilla raad bcrypt(hmac(password)) aan: https://wiki.mozilla.org/WebAppSec/Secure_Coding_Guidelines#Password_Storage
Gewijzigd op 08/03/2014 21:13:12 door Dos Moonen