Come si usa bcrypt per le password di hashing in PHP?


1256

Ogni tanto sento il consiglio "Usa bcrypt per archiviare le password in PHP, regole bcrypt".

Ma cos'è bcrypt? PHP non offre tali funzioni, Wikipedia parla di un'utilità di crittografia dei file e le ricerche sul Web rivelano solo alcune implementazioni di Blowfish in diverse lingue. Ora Blowfish è disponibile anche in PHP tramitemcrypt , ma in che modo aiuta a memorizzare le password? Blowfish è un codice generico, funziona in due modi. Se potrebbe essere crittografato, può essere decrittografato. Le password richiedono una funzione di hashing unidirezionale.

Qual è la spiegazione?


13
Questa domanda è stata affrontata in precedenza e il loro suggerimento di utilizzare una libreria standard è eccellente. La sicurezza è una questione complicata e usando un pacchetto progettato da qualcuno che sa cosa diavolo stanno facendo, ti stai solo aiutando.
eykanal,

59
@eykanal - quella pagina non menziona nemmeno bcrypt, tanto meno spiega di cosa si tratta .
Vilx-

8
@eykanal - Non chiedo una spiegazione di come funziona. Voglio solo sapere di cosa si tratta. Perché qualunque cosa riesca a scavare in rete con la parola chiave "bcrypt", non può in alcun modo essere utilizzata per le password di hashing. Non direttamente, comunque, e non in PHP. OK, ormai capisco che è davvero il pacchetto "phpass" che utilizza blowfish per crittografare la tua password con una chiave derivata dalla tua password (in sostanza crittografare la password con se stessa). Ma chiamarlo "bcrypt" è gravemente fuorviante, ed è quello che volevo chiarire in questa domanda.
Vilx-

3
@Vilx: ho aggiunto ulteriori informazioni sul perché bcryptè un algoritmo di hashing unidirezionale rispetto a uno schema di crittografia nella mia risposta . C'è tutto questo malinteso che bcryptè solo Blowfish quando in realtà ha un programma chiave totalmente diverso che assicura che il testo in chiaro non possa essere recuperato dal testo cifrato senza conoscere lo stato iniziale del codice (salt, rounds, key).
Andrew Moore,

1
Vedi anche Portable PHPass ( hashing framework PHPass) di Openwall. È indurito contro una serie di attacchi comuni alle password degli utenti.
jww

Risposte:


1065

bcryptè un algoritmo di hash che è scalabile con l'hardware (tramite un numero configurabile di round). La sua lentezza e i suoi molteplici round assicurano che un utente malintenzionato debba distribuire ingenti fondi e hardware per poter violare le password. Aggiungi a quei sali per password ( bcryptRICHIEDE sali) e puoi essere sicuro che un attacco è praticamente irrealizzabile senza una quantità ridicola di fondi o hardware.

bcryptutilizza l' algoritmo Eksblowfish per eseguire l'hash delle password. Mentre la fase di crittografia di Eksblowfish e Blowfish è esattamente la stessa, la fase di pianificazione delle chiavi di Eksblowfish garantisce che qualsiasi stato successivo dipenda sia da salt che da chiave (password utente) e che nessuno stato possa essere precompilato senza la conoscenza di entrambi. A causa di questa differenza fondamentale, bcryptè un algoritmo di hashing unidirezionale. Non è possibile recuperare la password del testo normale senza conoscere già il sale, i round e la chiave (password). [ Fonte ]

Come usare bcrypt:

Utilizzando PHP> = 5.5-DEV

Le funzioni di hashing delle password ora sono state integrate direttamente in PHP> = 5.5 . Ora puoi usare password_hash()per creare un bcrypthash di qualsiasi password:

<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

// Usage 2:
$options = [
  'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C

Per verificare la password fornita da un utente rispetto a un hash esistente, è possibile utilizzare password_verify()come tale:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}

Utilizzo di PHP> = 5.3.7, <5.5-DEV (anche RedHat PHP> = 5.3.3)

C'è una libreria di compatibilità su GitHub creata in base al codice sorgente delle funzioni di cui sopra originariamente scritto in C, che fornisce la stessa funzionalità. Una volta installata la libreria di compatibilità, l'utilizzo è lo stesso di cui sopra (meno la notazione dell'array abbreviata se si è ancora nel ramo 5.3.x).

Utilizzo di PHP <5.3.7 (DEPRECATED)

È possibile utilizzare la crypt()funzione per generare hash bcrypt di stringhe di input. Questa classe può generare automaticamente sali e verificare hash esistenti rispetto a un input. Se si utilizza una versione di PHP successiva o uguale a 5.3.7, si consiglia vivamente di utilizzare la funzione integrata o la libreria compat . Questa alternativa è fornita solo per scopi storici.

class Bcrypt{
  private $rounds;

  public function __construct($rounds = 12) {
    if (CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->rounds = $rounds;
  }

  public function hash($input){
    $hash = crypt($input, $this->getSalt());

    if (strlen($hash) > 13)
      return $hash;

    return false;
  }

  public function verify($input, $existingHash){
    $hash = crypt($input, $existingHash);

    return $hash === $existingHash;
  }

  private function getSalt(){
    $salt = sprintf('$2a$%02d$', $this->rounds);

    $bytes = $this->getRandomBytes(16);

    $salt .= $this->encodeBytes($bytes);

    return $salt;
  }

  private $randomState;
  private function getRandomBytes($count){
    $bytes = '';

    if (function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
      $bytes = openssl_random_pseudo_bytes($count);
    }

    if ($bytes === '' && is_readable('/dev/urandom') &&
       ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
      $bytes = fread($hRand, $count);
      fclose($hRand);
    }

    if (strlen($bytes) < $count) {
      $bytes = '';

      if ($this->randomState === null) {
        $this->randomState = microtime();
        if (function_exists('getmypid')) {
          $this->randomState .= getmypid();
        }
      }

      for ($i = 0; $i < $count; $i += 16) {
        $this->randomState = md5(microtime() . $this->randomState);

        if (PHP_VERSION >= '5') {
          $bytes .= md5($this->randomState, true);
        } else {
          $bytes .= pack('H*', md5($this->randomState));
        }
      }

      $bytes = substr($bytes, 0, $count);
    }

    return $bytes;
  }

  private function encodeBytes($input){
    // The following is code from the PHP Password Hashing Framework
    $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    $output = '';
    $i = 0;
    do {
      $c1 = ord($input[$i++]);
      $output .= $itoa64[$c1 >> 2];
      $c1 = ($c1 & 0x03) << 4;
      if ($i >= 16) {
        $output .= $itoa64[$c1];
        break;
      }

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 4;
      $output .= $itoa64[$c1];
      $c1 = ($c2 & 0x0f) << 2;

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 6;
      $output .= $itoa64[$c1];
      $output .= $itoa64[$c2 & 0x3f];
    } while (true);

    return $output;
  }
}

Puoi usare questo codice in questo modo:

$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);

In alternativa, puoi anche utilizzare il Portable PHP Hashing Framework .


7
@The Wicked Flea: mi dispiace deluderti, ma mt_rand()viene anche trasmesso utilizzando l'ora corrente e l'ID processo corrente. Si prega di vedere GENERATE_SEED()in/ext/standard/php_rand.h .
Andrew Moore,

53
@Mike: vai avanti, è lì proprio per questo motivo!
Andrew Moore,

14
Per chiunque pensi di dover modificare l'inizio della stringa $ salt nella funzione getSalt, ciò non è necessario. $ 2a $ __ fa parte del sale CRYPT_BLOWFISH. Dai documenti: "Blowfish hashing con un sale come segue:" $ 2a $ ", un parametro di costo a due cifre," $ "e 22 cifre dell'alfabeto".
jwinn,

18
@MichaelLang: la cosa buona crypt()è quindi rivista e verificata. Il codice sopra chiama PHP crypt(), che chiama la crypt()funzione POSIX . Tutto il codice sopra fa di più è generare un salt casuale (che non deve essere crittograficamente sicuro, il salt non è considerato un segreto) prima di chiamare crypt(). Forse dovresti fare delle ricerche prima di chiamare il lupo.
Andrew Moore,

31
Questa risposta, sebbene buona, sta iniziando a mostrare la sua età. Questo codice (come qualsiasi implementazione di PHP su cui si basa crypt()) è soggetto a una vulnerabilità di sicurezza pre-5.3.7 ed è (leggermente) inefficiente dopo-5.3.7 - i dettagli del problema rilevante sono disponibili qui . Si noti inoltre che la nuova API di hashing delle password (versione precedente compatibile ) è ora il metodo preferito per implementare l'hash delle password bcrypt nella propria applicazione.
DaveRandom,

295

Quindi, vuoi usare bcrypt? Eccezionale!Tuttavia, come altre aree della crittografia, non dovresti farlo da solo. Se devi preoccuparti di qualcosa come la gestione delle chiavi, la memorizzazione di sali o la generazione di numeri casuali, stai sbagliando.

Il motivo è semplice: è così banalmente facile rovinare bcrypt . In effetti, se guardi quasi ogni parte di codice in questa pagina, noterai che sta violando almeno uno di questi problemi comuni.

Ammettilo, la crittografia è difficile.

Lascialo per gli esperti. Lascialo per le persone il cui compito è mantenere queste librerie. Se devi prendere una decisione, la stai sbagliando.

Invece, basta usare una libreria. Ne esistono diversi a seconda delle tue esigenze.

biblioteche

Ecco una ripartizione di alcune delle API più comuni.

API PHP 5.5 - (disponibile per 5.3.7+)

A partire da PHP 5.5, viene introdotta una nuova API per le password di hashing. C'è anche una libreria di compatibilità shim mantenuta (da me) per 5.3.7+. Questo ha il vantaggio di essere un'implementazione peer-reviewed e semplice da usare.

function register($username, $password) {
    $hash = password_hash($password, PASSWORD_BCRYPT);
    save($username, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    if (password_verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Davvero, mira ad essere estremamente semplice.

risorse:

Zend \ Crypt \ Password \ Bcrypt (5.3.2+)

Questa è un'altra API simile a quella di PHP 5.5 e ha uno scopo simile.

function register($username, $password) {
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    $hash = $bcrypt->create($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $bcrypt = new Zend\Crypt\Password\Bcrypt();
    if ($bcrypt->verify($password, $hash)) {
        //login
    } else {
        // failure
    }
}

risorse:

PasswordLib

Questo è un approccio leggermente diverso all'hash delle password. Anziché supportare semplicemente bcrypt, PasswordLib supporta un gran numero di algoritmi di hashing. È utile soprattutto in contesti in cui è necessario supportare la compatibilità con sistemi legacy e disparati che potrebbero essere al di fuori del proprio controllo. Supporta un gran numero di algoritmi di hashing. Ed è supportato 5.3.2+

function register($username, $password) {
    $lib = new PasswordLib\PasswordLib();
    $hash = $lib->createPasswordHash($password, '$2y$', array('cost' => 12));
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $lib = new PasswordLib\PasswordLib();
    if ($lib->verifyPasswordHash($password, $hash)) {
        //login
    } else {
        // failure
    }
}

Riferimenti:

  • Codice sorgente / Documentazione: GitHub

PHPASS

Questo è un livello che supporta bcrypt, ma supporta anche un algoritmo abbastanza potente utile se non si ha accesso a PHP> = 5.3.2 ... In realtà supporta PHP 3.0+ (anche se non con bcrypt).

function register($username, $password) {
    $phpass = new PasswordHash(12, false);
    $hash = $phpass->HashPassword($password);
    save($user, $hash);
}

function login($username, $password) {
    $hash = loadHashByUsername($username);
    $phpass = new PasswordHash(12, false);
    if ($phpass->CheckPassword($password, $hash)) {
        //login
    } else {
        // failure
    }
}

risorse

Nota: non utilizzare le alternative PHPASS che non sono ospitate su openwall, sono progetti diversi !!!

Informazioni su BCrypt

Se noti, ognuna di queste librerie restituisce una singola stringa. Ciò è dovuto al modo in cui BCrypt funziona internamente. E ci sono un sacco di risposte a riguardo. Ecco una selezione che ho scritto, che non copierò / incollerò qui, ma rimanderò a:

Incartare

Ci sono molte scelte diverse. Quale scegli dipende da te. Tuttavia, vorrei ALTAMENTE consiglia di utilizzare una delle librerie di cui sopra per la gestione di questo per voi.

Ancora una volta, se stai usando crypt()direttamente, probabilmente stai facendo qualcosa di sbagliato. Se il tuo codice utilizza hash()(o md5()o sha1()) direttamente, stai quasi sicuramente facendo qualcosa di sbagliato.

Usa una libreria ...


7
Il sale deve essere generato in modo casuale, tuttavia non deve provenire da una fonte casuale sicura. Il sale non è un segreto . Essere in grado di indovinare il prossimo sale non ha alcun reale impatto sulla sicurezza; fintanto che provengono da un pool di dati sufficientemente grande da generare sali diversi per ogni password codificata, si sta bene. Ricorda, il sale è lì per impedire l'uso di tavoli arcobaleno se i tuoi hash arrivano in cattive mani. Non sono segreti.
Andrew Moore,

7
@AndrewMoore assolutamente corretto! Tuttavia, il sale deve avere abbastanza entropia per essere statisticamente unico. Non solo nella tua applicazione, ma in tutte le applicazioni. Quindi mt_rand()ha un periodo abbastanza alto, ma il valore del seme è solo 32 bit. Quindi l'uso mt_rand()efficace ti limita a soli 32 bit di entropia. Ciò grazie al problema del compleanno significa che hai una probabilità del 50% di collisione a soli 7k sali generati (a livello globale). Dato che bcryptaccetta 128 bit di sale, è meglio usare una fonte in grado di fornire tutti i 128 bit ;-). (a 128 bit, il 50% di probabilità di collisione si verifica con hash 2e19) ...
ircmaxell,

1
@ircmaxell: Hense il "pool di dati sufficientemente ampio". Tuttavia, la tua sorgente non deve essere una sorgente di entropia MOLTO ALTA, abbastanza alta per i 128 bit. Tuttavia, se hai esaurito tutte le tue fonti disponibili (non hai OpenSSL, ecc ...) e il tuo unico fallback è mt_rand (), è comunque migliore dell'alternativa (che è rand ()).
Andrew Moore,

4
@AndrewMoore: assolutamente. Non discuterne. Solo che mt_rande uniqid(e quindi lcg_valuee rand) non sono le prime scelte ...
ircmaxell,

1
ircmaxell, grazie mille per la libreria password_compat per 5.3.xx, non ne abbiamo mai avuto bisogno prima, ma ora lo facciamo, su un server php 5.3.xx, e grazie per il tuo chiaro consiglio di non provare a fare questa logica se stessi.
Lizardx,

47

Otterrai molte informazioni in Basta con The Rainbow Tables: cosa devi sapere sugli schemi di password sicure o sul framework di hashing delle password PHP portatile .

L'obiettivo è hash della password con qualcosa di lento, quindi qualcuno che ottiene il tuo database delle password morirà nel tentativo di forzare la forza (un ritardo di 10 ms per controllare una password non fa per te, molto per qualcuno che cerca di forzare la forza). Bcrypt è lento e può essere utilizzato con un parametro per scegliere quanto è lento.


7
Applicare quello che vuoi, gli utenti riusciranno a rovinare e utilizzare la stessa password su più cose. Quindi devi proteggerlo il più possibile o implementare qualcosa che ti consenta di non dover memorizzare alcuna password (SSO, openID ecc.).
Arkh,

41
No. L'hash delle password viene utilizzato per proteggere da un attacco: qualcuno ha rubato il tuo database e desidera ottenere login + password in chiaro.
Arkh,

4
@Josh K. Ti incoraggio a provare a decifrare alcune semplici password dopo averle sintonizzate su phpass in modo che siano necessari tra 1ms e 10ms per calcolarlo sul tuo server web.
Arkh,

3
Concordato. Ma il tipo di utente che utilizzerà qwerty come password è anche il tipo di utente che contrassegnerà qualsiasi complicato da qualche parte (lui e gli aggressori) possono facilmente leggerlo. Quello che usa bcrypt è che quando il tuo db diventa pubblico contro la tua volontà, sarà più difficile arrivare a quegli utenti che hanno una password come ^ | $$ & ZL6- £ che se avessi usato sha512 in un solo passaggio.
Arkh,

4
@coreyward vale la pena notare che farlo è più dannoso del non bloccare affatto; che è facilmente considerato un vettore di "negazione del servizio". Inizia a inviare spam con accessi non validi su qualsiasi account noto e puoi interrompere molti utenti molto, molto facilmente. È meglio tarpit (ritardare) l'attaccante piuttosto che negare l'accesso, soprattutto se si tratta di un cliente pagante.
damianb,

36

Puoi creare un hash unidirezionale con bcrypt usando la crypt()funzione di PHP e passando un sale Blowfish appropriato. La più importante di tutta l'equazione è che A) l'algoritmo non è stato compromesso e B) si sale correttamente ogni password . Non utilizzare un sale a livello di applicazione; che apre l'intera applicazione per attaccare da un singolo set di tabelle Rainbow.

PHP - Funzione Crypt


4
Questo è l'approccio giusto: usa la crypt()funzione di PHP , che supporta diverse funzioni di hashing delle password. Assicurati di non utilizzare CRYPT_STD_DESo CRYPT_EXT_DES- nessuno degli altri tipi supportati va bene (e include bcrypt, sotto il nome CRYPT_BLOWFISH).
Caf

4
SHA ha anche un parametro di costo, tramite l'opzione 'rounds'. Quando lo uso, non vedo anche alcun motivo per favorire bcrypt.
Pieter Ennes,

3
In realtà, un singolo SHA-1 (o MD5) di una password è ancora facilmente in grado di forzare la forza bruta, con o senza sale (il sale aiuta contro i tavoli arcobaleno, non contro la forza bruta). Usa bcrypt.
Paŭlo Ebermann,

Trovo inquietante che tutti sembrano dire "bcrypt" quando intendono php's crypt ().
Sliq,

3
@Panique Perché? L'algoritmo si chiama bcrypt . cryptespone diversi hash di password, con bcrypt corrispondente alla CRYPT_BLOWFISHcostante. Bcrypt è attualmente l'algoritmo più potente supportato da crypte molti altri che supporta sono abbastanza deboli.
CodesInChaos,

34

Modifica: 2013.01.15 - Se il tuo server lo supporterà, usa invece la soluzione di martinstoeckli .


Tutti vogliono renderlo più complicato di quello che è. La funzione crypt () svolge la maggior parte del lavoro.

function blowfishCrypt($password,$cost)
{
    $chars='./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $salt=sprintf('$2y$%02d$',$cost);
//For PHP < PHP 5.3.7 use this instead
//    $salt=sprintf('$2a$%02d$',$cost);
    //Create a 22 character salt -edit- 2013.01.15 - replaced rand with mt_rand
    mt_srand();
    for($i=0;$i<22;$i++) $salt.=$chars[mt_rand(0,63)];
    return crypt($password,$salt);
}

Esempio:

$hash=blowfishCrypt('password',10); //This creates the hash
$hash=blowfishCrypt('password',12); //This creates a more secure hash
if(crypt('password',$hash)==$hash){ /*ok*/ } //This checks a password

So che dovrebbe essere ovvio, ma per favore non usare "password" come password.


3
La creazione del sale potrebbe essere migliorata (utilizzare la fonte casuale del sistema operativo), altrimenti mi sembra buono. Per le nuove versioni di PHP è meglio usare 2yinvece di 2a.
martinstoeckli,

usare mcrypt_create_iv($size, MCRYPT_DEV_URANDOM)come fonte per il sale.
Codici A Caos

Daremo un'occhiata più da vicino a mcrypt_create_iv () quando avrò un momento, se non altro dovrebbe migliorare leggermente le prestazioni.
Jon Hulka,

2
Aggiungi la codifica Base64 e traduci negli usi dell'alfabeto personalizzato bcrypt. mcrypt_create_iv(17, MCRYPT_DEV_URANDOM), str_replace('+', '.', base64_encode($rawSalt)),$salt = substr($salt, 0, 22);
CodesInChaos

1
@JonHulka - Dai un'occhiata al pacchetto di compatibilità di PHP [Linea 127], questa è un'implementazione semplice.
martinstoeckli,

29

La versione 5.5 di PHP avrà il supporto integrato per BCrypt, le funzioni password_hash()e password_verify(). In realtà questi sono solo involucri attorno alla funzione crypt()e devono renderlo più facile da usare correttamente. Si occupa della generazione di un sale casuale sicuro e fornisce buoni valori predefiniti.

Il modo più semplice per utilizzare queste funzioni sarà:

$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

Questo codice eseguirà l'hashing della password con BCrypt (algoritmo 2y), genera un salt casuale dalla fonte casuale del SO e utilizza il parametro di costo predefinito (al momento è 10). La seconda riga verifica se l'utente ha inserito una password corrispondente a un valore hash già memorizzato.

Se si desidera modificare il parametro di costo, è possibile farlo in questo modo, aumentando il parametro di costo di 1, raddoppiando il tempo necessario per calcolare il valore di hash:

$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 11));

Contrariamente al "cost"parametro, è meglio omettere il "salt"parametro, poiché la funzione fa già del suo meglio per creare un sale crittograficamente sicuro.

Per PHP versione 5.3.7 e successive, esiste un pacchetto di compatibilità , dello stesso autore che ha creato la password_hash()funzione. Per le versioni PHP precedenti alla 5.3.7 non è supportato crypt()con 2yl'algoritmo BCrypt sicuro Unicode. Si potrebbe invece sostituirlo con 2a, che è la migliore alternativa per le precedenti versioni di PHP.


3
Dopo aver letto questo, il mio primo pensiero è stato "come si conserva il sale che viene generato"? Dopo aver sfogliato i documenti, la funzione password_hash () finisce per generare una stringa che memorizza il metodo di crittografia, il salt e l'hash generato. Quindi, memorizza tutto ciò di cui ha bisogno in una stringa per far funzionare la funzione password_verify (). Volevo solo menzionarlo perché potrebbe aiutare gli altri a vederlo.
jzimmerman2011,

@ jzimmerman2011 - Esatto, in un'altra risposta ho provato a spiegare questo formato di archiviazione con un esempio.
martinstoeckli,

7

Pensiero attuale: gli hash dovrebbero essere i più lenti disponibili, non i più veloci possibili. Questo elimina gli attacchi da tavolo arcobaleno .

Anche correlato, ma precauzionale: un utente malintenzionato non dovrebbe mai avere accesso illimitato alla schermata di accesso. Per evitarlo: imposta una tabella di tracciamento dell'indirizzo IP che registri ogni hit insieme all'URI. Se più di 5 tentativi di accesso provengono dallo stesso indirizzo IP in un periodo di cinque minuti, bloccare con spiegazione. Un approccio secondario è quello di avere uno schema di password a due livelli, come fanno le banche. Mettere un blocco per errori sul secondo passaggio aumenta la sicurezza.

Riepilogo: rallenta l'attaccante utilizzando le funzioni hash che richiedono tempo. Inoltre, blocca troppi accessi al tuo login e aggiungi un secondo livello di password.


Penso che presumano che l'attaccante sia già riuscito a rubare il mio DB in qualche altro modo, e ora sta cercando di ottenere le password per provarle su paypal o qualcosa del genere.
Vilx-

4
A metà del 2012 e questa risposta è ancora traballante, in che modo un algoritmo di hashing lento impedisce gli attacchi da tavolo arcobaleno? Ho pensato che fosse saltato un intervallo di byte casuali? Ho sempre pensato che la velocità dell'algoritmo di hashing imponesse quante iterazioni possono inviare contro l'hash che hanno ottenuto da te in un determinato periodo di tempo. Inoltre, MAI BLOCCARE MAI UN UTENTE SU TENTATIVI DI ACCESSO NON RIUSCITI fidati che i tuoi utenti si stanchino, spesso su alcuni siti ho bisogno di accedere quasi 5 volte a volte prima di ricordare la mia password. Anche il secondo passaggio non funziona, ma potrebbe essere possibile utilizzare l'autenticazione in due passaggi con il codice del cellulare.
Sammaye,

1
@Sammaye Sono d'accordo con questo fino a un certo punto. Ho impostato un blocco su 5 tentativi di accesso non riusciti, prima di portarlo rapidamente a 7, quindi 10 ora seduto su 20. Nessun utente normale dovrebbe avere 20 tentativi di accesso falliti ma è abbastanza basso da fermare facilmente gli attacchi di forza bruta
Bruce Aldridge

@BruceAldridge Personalmente penso che sarebbe meglio mettere in pausa il tuo script per un tempo casuale dopo dire, 7 accessi falliti e mostrare un captcha piuttosto che un blocco. Il blocco è una mossa molto aggressiva da prendere.
Sammaye,

1
@Sammaye Sono d'accordo che i blocchi permanenti sono cattivi. Mi riferisco a un blocco temporaneo che aumenta con il numero di tentativi falliti.
Bruce Aldridge,

7

Ecco una risposta aggiornata a questa vecchia domanda!

Il modo giusto per hash delle password in PHP è 5.5 password_hash()e il modo giusto per verificarle è con password_verify(), e questo è ancora vero in PHP 8.0. Queste funzioni usano hash bcrypt per impostazione predefinita, ma sono stati aggiunti altri algoritmi più potenti. È possibile modificare il fattore di lavoro (effettivamente quanto "forte" è la crittografia) tramite i password_hashparametri.

Tuttavia, mentre è ancora abbastanza forte, bcrypt non è più considerato all'avanguardia ; un migliore set di algoritmi di hash delle password è arrivato chiamato Argon2 , con le varianti Argon2i, Argon2d e Argon2id. La differenza tra loro (come descritto qui ):

Argon2 ha una variante primaria: Argon2id e due varianti supplementari: Argon2d e Argon2i. Argon2d utilizza l'accesso alla memoria dipendente dai dati, che lo rende adatto per le criptovalute e le applicazioni di prova di lavoro senza minacce da attacchi di temporizzazione del canale laterale. Argon2i utilizza l'accesso alla memoria indipendente dai dati, che è preferito per l'hash della password e la derivazione della chiave basata su password. Argon2id funziona come Argon2i per la prima metà della prima iterazione sulla memoria e come Argon2d per il resto, fornendo così sia la protezione dagli attacchi del canale laterale sia risparmi sui costi della forza bruta a causa di compromessi della memoria temporale.

Il supporto per Argon2i è stato aggiunto in PHP 7.2 e lo richiedi in questo modo:

$hash = password_hash('mypassword', PASSWORD_ARGON2I);

e il supporto Argon2id è stato aggiunto in PHP 7.3:

$hash = password_hash('mypassword', PASSWORD_ARGON2ID);

Non sono necessarie modifiche per la verifica delle password poiché la stringa di hash risultante contiene informazioni su quali algoritmo, salt e fattori di lavoro sono stati utilizzati al momento della creazione.

Abbastanza separatamente (e in qualche modo ridondante), libsodium (aggiunto in PHP 7.2) fornisce anche l'hashing di Argon2 tramite le funzioni sodium_crypto_pwhash_str ()e sodium_crypto_pwhash_str_verify(), che funzionano allo stesso modo dei built-in PHP. Una possibile ragione per l'uso di questi è che a volte PHP può essere compilato senza libargon2, il che rende gli algoritmi Argon2 non disponibili per la funzione password_hash; PHP 7.2 e versioni successive dovrebbero sempre avere libsodium abilitato, ma potrebbe non esserlo - ma almeno ci sono due modi per ottenere quell'algoritmo. Ecco come è possibile creare un hash Argon2id con libsodium (anche in PHP 7.2, che altrimenti non ha il supporto Argon2id)):

$hash = sodium_crypto_pwhash_str(
    'mypassword',
    SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
    SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

Si noti che non consente di specificare manualmente un sale; questo fa parte dell'ethos di libsodium - non permettere agli utenti di impostare parametri su valori che potrebbero compromettere la sicurezza - per esempio non c'è nulla che ti impedisca di passare una stringa di sale vuota alla password_hashfunzione di PHP ; libsodium non ti consente di fare nulla di così sciocco!


4

Per le password di OAuth 2 :

$bcrypt = new \Zend\Crypt\Password\Bcrypt;
$bcrypt->create("youpasswordhere", 10)

1

Come tutti sappiamo, archiviare la password in chiaro nel database non è sicuro. bcrypt è una tecnica con password di hashing, utilizzata per creare la sicurezza delle password. una delle incredibili funzioni di bcrypt è che ci salva dagli hacker, è usato per proteggere la password dagli attacchi di hacking perché la password è memorizzata in forma criptata.

la funzione password_hash () viene utilizzata per creare un nuovo hash password. Utilizza un algoritmo di hashing forte e robusto. La funzione password_hash () è molto compatibile con la funzione crypt (). Pertanto, gli hash delle password creati da crypt () possono essere utilizzati con password_hash () e viceversa. Le funzioni password_verify () e password_hash () sono solo i wrapper attorno alla funzione crypt () e rendono molto più facile usarlo con precisione.

SINTASSI

string password_hash($password , $algo , $options)

I seguenti algoritmi sono attualmente supportati dalla funzione password_hash ():

PASSWORD_DEFAULT PASSWORD_BCRYPT PASSWORD_ARGON2I PASSWORD_ARGON2ID

Parametri: questa funzione accetta tre parametri come indicato sopra e descritto di seguito:

password : memorizza la password dell'utente. algo : è la costante dell'algoritmo della password che viene utilizzata continuamente mentre indica l'algoritmo che deve essere utilizzato quando si verifica l'hash della password. opzioni : è un array associativo, che contiene le opzioni. Se questo viene rimosso e non include, verrà utilizzato un salt casuale e verrà utilizzato l'utilizzo di un costo predefinito. Valore di ritorno : restituisce la password con hash in caso di successo o Falso in caso di fallimento.

Esempio :

Input : echo password_hash("GFG@123", PASSWORD_DEFAULT); Output : $2y$10$.vGA19Jh8YrwSJFDodbfoHJIOFH)DfhuofGv3Fykk1a

Di seguito i programmi illustrano la funzione password_hash () in PHP:

<?php echo password_hash("GFG@123", PASSWORD_DEFAULT); ?>

PRODUZIONE

$2y$10$Z166W1fBdsLcXPVQVfPw/uRq1ueWMA6sLt9bmdUFz9AmOGLdM393G

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.