PHP
Lösenord Hashing-funktioner
Sök…
Introduktion
Eftersom säkrare webbtjänster undviker att lagra lösenord i vanlig textformat, erbjuder språk som PHP olika (okrypterbara) hashfunktioner för att stödja den säkrare industristandarden. Det här ämnet ger dokumentation för korrekt hashing med PHP.
Syntax
-
string password_hash ( string $password , integer $algo [, array $options ] )
-
boolean password_verify ( string $password , string $hash )
-
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
-
array password_get_info ( string $hash )
Anmärkningar
Innan PHP 5.5 kan du använda kompatibilitetspaketet för att tillhandahålla password_*
-funktionerna. Det rekommenderas starkt att du använder kompatibilitetspaketet om du kan göra det.
Med eller utan kompatibilitetspaketet, korrigerar Bcrypt-funktionalitet via crypt()
förlitar sig på PHP 5.3.7+, annars måste du begränsa lösenord till ASCII-teckenuppsättningar.
Obs! Om du använder PHP 5.5 eller senare använder du en version som inte stöds av PHP som inte längre får några säkerhetsuppdateringar. Uppdatera så snart som möjligt, du kan uppdatera ditt lösenord hash efteråt.
Algoritmval
Säkra algoritmer
- bcrypt är ditt bästa alternativ så länge du använder tangentsträckning för att öka hashberäkningstiden, eftersom det gör brute force attackerna extremt långsam .
- argon2 är ett annat alternativ som kommer att finnas tillgängligt i PHP 7.2 .
Osäkra algoritmer
Följande hashningsalgoritmer är osäkra eller olämpliga för syfte och bör därför inte användas . De var aldrig lämpade för hashning av lösenord, eftersom de är utformade för snabba smälter istället för långsam och svår att brute kraft lösenord hash.
Om du använder någon av dem , även inklusive salter, bör du byta till en av de rekommenderade säkra algoritmerna så snart som möjligt .
Algoritmer anses vara osäkra:
- MD4 - kollisionsattack hittades 1995
- MD5 - kollisionsattack hittades 2005
- SHA-1 - kollisionsattack demonstrerad 2015
Vissa algoritmer kan på ett säkert sätt användas som algoritmer för meddelandetillförsel för att bevisa äkthet, men aldrig som algoritmer för hashing-lösenord :
- SHA-2
- SHA-3
Observera att starka hascher som SHA256 och SHA512 är obrutna och robusta, men det är i allmänhet säkrare att använda bcrypt- eller argon2- hashfunktioner eftersom brute-kraftattacker mot dessa algoritmer är mycket svårare för klassiska datorer.
Bestäm om ett befintligt lösenord hash kan uppgraderas till en starkare algoritm
Om du använder PASSWORD_DEFAULT
metoden för att låta systemet välja den bästa algoritmen att hash dina lösenord med, eftersom standardinställningen ökar i styrka kanske du vill omväxla gamla lösenord när användare loggar in
<?php
// first determine if a supplied password is valid
if (password_verify($plaintextPassword, $hashedPassword)) {
// now determine if the existing hash was created with an algorithm that is
// no longer the default
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
// create a new hash with the new default
$newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT);
// and then save it to your data store
//$db->update(...);
}
}
?>
Om lösenord_funktionerna inte är tillgängliga på ditt system (och du inte kan använda kompatibilitetspaketet länkat i kommentarerna nedan) kan du bestämma algoritmen och använda för att skapa den ursprungliga hash på en metod som liknar följande:
<?php
if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) {
echo 'Algorithm is Bcrypt';
// the "cost" determines how strong this version of Bcrypt is
preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches);
$cost = $matches[1];
echo 'Bcrypt cost is '.$cost;
}
?>
Skapa ett lösenord hash
Skapa lösenord hash med password_hash()
att använda den nuvarande branschen för bästa praktik-hash eller nyckeldivation. I skrivande stund är standarden bcrypt , vilket innebär att PASSWORD_DEFAULT
innehåller samma värde som PASSWORD_BCRYPT
.
$options = [
'cost' => 12,
];
$hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options);
Den tredje parametern är inte obligatorisk .
Värdet 'cost'
bör väljas baserat på din produktionsserver hårdvara. Att öka det kommer att göra lösenordet dyrare att generera. Ju dyrare det är att generera desto längre tid tar det någon som försöker knäcka den att generera den också. Kostnaden bör idealiskt vara så hög som möjligt, men i praktiken bör den ställas in så att den inte bromsar allt för mycket. Någonstans mellan 0,1 och 0,4 sekunder skulle det vara okej. Använd standardvärdet om du är osäker.
På PHP lägre än 5.5.0 är password_*
inte tillgängliga. Du bör använda kompatibilitetspaketet för att ersätta dessa funktioner. Lägg märke till att kompatibilitetspaketet kräver PHP 5.3.7 eller högre eller en version som har $2y
fixet tillbaka i det (som RedHat tillhandahåller).
Om du inte kan använda dessa kan du implementera lösenord hashing med crypt()
Eftersom password_hash()
är implementerat som ett omslag runt funktionen crypt()
behöver du inte förlora någon funktionalitet.
// this is a simple implementation of a bcrypt hash otherwise compatible
// with `password_hash()`
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
// if `CRYPT_BLOWFISH` is 1, that means bcrypt (which uses blowfish) is available
// on your system
if (CRYPT_BLOWFISH == 1) {
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$salt = base64_encode($salt);
// crypt uses a modified base64 variant
$source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$dest = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt = strtr(rtrim($salt, '='), $source, $dest);
$salt = substr($salt, 0, 22);
// `crypt()` determines which hashing algorithm to use by the form of the salt string
// that is passed in
$hashedPassword = crypt($plaintextPassword, '$2y$10$'.$salt.'$');
}
Salt för lösenord hash
Trots pålitlighet hos kryptalgoritmen finns det fortfarande sårbarhet mot regnbågens bord . Det är anledningen, varför det rekommenderas att använda salt .
Ett salt är något som läggs till i lösenordet innan hashing för att göra källsträngen unik. Med två identiska lösenord kommer de resulterande hasherna också att vara unika eftersom deras salter är unika.
Ett slumpmässigt salt är en av de viktigaste delarna av ditt lösenordssäkerhet. Detta innebär att även med en uppslagstabell med kända lösenord hascher kan en angripare inte matcha din användares lösenord hash med databaslösenord hash eftersom ett slumpmässigt salt har använts. Du bör alltid använda slumpmässiga och kryptografiskt säkra salter. Läs mer
Med password_hash()
bcrypt
algoritm lagras vanlig textsalt tillsammans med den resulterande hash, vilket innebär att hash kan överföras över olika system och plattformar och fortfarande matchas mot det ursprungliga lösenordet.
Även när detta motverkas, kan du använda salt
möjlighet att definiera din egen random salt.
$options = [
'salt' => $salt, //see example below
];
Viktigt . Om du utelämnar detta alternativ kommer ett slumpmässigt salt att genereras av password_hash () för varje lösenord hashed. Detta är det avsedda driftsläget.
Saltalternativet har avskrivits från och med PHP 7.0.0. Det är nu föredraget att helt enkelt använda saltet som genereras som standard.
Verifierar ett lösenord mot en hash
password_verify()
är den inbyggda funktionen som tillhandahålls (från och med PHP 5.5) för att verifiera giltigheten av ett lösenord mot en känd hash.
<?php
if (password_verify($plaintextPassword, $hashedPassword)) {
echo 'Valid Password';
}
else {
echo 'Invalid Password.';
}
?>
Alla stötta hashalgoritmer lagrar information som identifierar vilken hash som användes i själva hash, så det finns inget behov att ange vilken algoritm du använder för att koda klartextlösenordet med.
Om lösenord_funktionerna inte är tillgängliga på ditt system (och du inte kan använda kompatibilitetspaketet som är länkat i kommentarerna nedan) kan du implementera lösenordsverifiering med funktionen crypt()
. Observera att specifika försiktighetsåtgärder måste vidtas för att undvika timingattacker .
<?php
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
if (CRYPT_BLOWFISH == 1) {
// `crypt()` discards all characters beyond the salt length, so we can pass in
// the full hashed password
$hashedCheck = crypt($plaintextPassword, $hashedPassword);
// this a basic constant-time comparison based on the full implementation used
// in `password_hash()`
$status = 0;
for ($i=0; $i<strlen($hashedCheck); $i++) {
$status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i]));
}
if ($status === 0) {
echo 'Valid Password';
}
else {
echo 'Invalid Password';
}
}
?>