Frage Wie benutzt man bcrypt zum Hashing von Passwörtern in PHP?


Hin und wieder höre ich den Hinweis "Benutze bcrypt zum Speichern von Passwörtern in PHP, bcrypt-Regeln".

Aber was ist bcrypt? PHP bietet keine solchen Funktionen, Wikipedia plappert über ein Datei-Verschlüsselungs-Dienstprogramm und Web-Suchen zeigen nur ein paar Implementierungen von Kugelfisch in verschiedenen Sprachen. Jetzt ist Blowfish auch in PHP verfügbar mcrypt, aber wie hilft das beim Speichern von Passwörtern? Blowfish ist eine allgemeine Chiffre, es funktioniert auf zwei Arten. Wenn es verschlüsselt werden könnte, kann es entschlüsselt werden. Passwörter benötigen eine Einweg-Hashing-Funktion.

Was ist die Erklärung?


1145
2018-01-25 15:34


Ursprung


Antworten:


bcrypt ist ein Hashalgorithmus, der mit der Hardware skalierbar ist (über eine konfigurierbare Anzahl von Runden). Seine Langsamkeit und mehrere Runden stellen sicher, dass ein Angreifer massive Mittel und Hardware bereitstellen muss, um Ihre Kennwörter knacken zu können. Fügen Sie das per Passwort hinzu Salze (bcrypt Erfordert Salze) und Sie können sicher sein, dass ein Angriff praktisch unmöglich ist, ohne entweder lächerlich Geld oder Hardware.

bcrypt nutzt die Eksblowfish Algorithmus zum Hash Passwörter. Während der Verschlüsselungsphase von Eksblowfish und Kugelfisch sind genau die gleichen, die wichtigsten Zeitplan-Phase von Eksblowfish stellt sicher, dass jeder nachfolgende Status sowohl von "salt" als auch von "key" (Benutzerkennwort) abhängt und dass kein Zustand ohne die Kenntnis beider vorausberechnet werden kann. Wegen dieses Schlüsselunterschiedes bcrypt ist ein Einweg-Hashalgorithmus. Sie können das Klartext-Passwort nicht abrufen, ohne bereits das Salz oder die Runden zu kennen und Schlüssel (Passwort). [Quelle]

Wie benutze ich bcrypt:

Mit PHP> = 5.5-DEV

Password Hashing Funktionen sind jetzt direkt in PHP> = 5.5 eingebaut. Sie können jetzt verwenden password_hash() ein erstellen bcrypt Hash eines beliebigen Passworts:

<?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

Um ein vom Benutzer angegebenes Passwort gegen einen vorhandenen Hash zu verifizieren, können Sie den password_verify() so wie:

<?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.';
}

Mit PHP> = 5.3.7, <5.5-DEV (auch RedHat PHP> = 5.3.3)

Da ist ein Kompatibilitätsbibliothek auf GitHub erstellt auf der Grundlage des Quellcodes der oben genannten Funktionen ursprünglich in C geschrieben, die die gleiche Funktionalität bietet. Sobald die Kompatibilitätsbibliothek installiert ist, ist die Verwendung die gleiche wie oben (abzüglich der Schreibweise des Kurzformats, wenn Sie sich noch im Zweig 5.3.x befinden).

Mit PHP <5.3.7 (Veraltet)

Sie können verwenden crypt() Funktion zum Erzeugen von bcrypt-Hashes von Eingabe-Strings. Diese Klasse kann automatisch Salze generieren und bestehende Hashes gegen eine Eingabe verifizieren. Wenn Sie eine Version von PHP höher oder gleich 5.3.7 verwenden, wird dringend empfohlen, die integrierte Funktion oder die compat-Bibliothek zu verwenden. Diese Alternative ist nur für historische Zwecke vorgesehen.

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;
  }
}

Sie können diesen Code wie folgt verwenden:

$bcrypt = new Bcrypt(15);

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

Alternativ können Sie auch die Portables PHP Hashing Framework.


973
2018-06-12 19:23



Also, willst du bcrypt benutzen? Genial! Wie in anderen Bereichen der Kryptographie sollten Sie dies jedoch nicht selbst tun. Wenn Sie sich um die Verwaltung von Schlüsseln oder das Speichern von Salzen oder das Generieren von Zufallszahlen kümmern müssen, tun Sie es falsch.

Der Grund ist einfach: es ist so trivial einfach vermasseln bcrypt. In der Tat, wenn Sie sich fast jedes Stück Code auf dieser Seite ansehen, werden Sie bemerken, dass es mindestens eines dieser üblichen Probleme verletzt.

Stellen Sie es, Kryptografie ist schwer.

Überlassen Sie es den Experten. Überlassen Sie es den Leuten, deren Aufgabe es ist, diese Bibliotheken zu pflegen. Wenn Sie eine Entscheidung treffen müssen, machen Sie es falsch.

Verwenden Sie stattdessen einfach eine Bibliothek. Abhängig von Ihren Anforderungen existieren mehrere.

Bibliotheken

Im Folgenden finden Sie eine Aufschlüsselung einiger der gängigsten APIs.

PHP 5.5 API - (Verfügbar für 5.3.7+)

Ab PHP 5.5 wird eine neue API zum Hashing von Passwörtern eingeführt. Es gibt auch eine Shimkompatibilitätsbibliothek (von mir) für 5.3.7+. Dies hat den Vorteil, dass sie von Experten geprüft werden einfach Implementierung verwenden.

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
    }
}

Wirklich, es zielt darauf ab, extrem einfach zu sein.

Ressourcen:

Zend \ Crypt \ Passwort \ Bcrypt (5.3.2+)

Dies ist eine andere API, die der PHP 5.5 ähnlich ist und einen ähnlichen Zweck erfüllt.

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
    }
}

Ressourcen:

PasswortLib

Dies ist ein etwas anderer Ansatz für das Password Hashing. Anstatt bcrypt einfach zu unterstützen, unterstützt PasswordLib eine große Anzahl von Hashing-Algorithmen. Es ist hauptsächlich in Kontexten nützlich, in denen Sie die Kompatibilität mit älteren und unterschiedlichen Systemen unterstützen müssen, die sich außerhalb Ihrer Kontrolle befinden. Es unterstützt eine große Anzahl von Hashalgorithmen. Und wird unterstützt 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
    }
}

Verweise:

  • Quellcode / Dokumentation: GitHub

PHPASS

Dies ist ein Layer, der bcrypt unterstützt, aber auch einen ziemlich starken Algorithmus unterstützt, der nützlich ist, wenn Sie keinen Zugriff auf PHP> = 5.3.2 haben. Er unterstützt tatsächlich PHP 3.0+ (allerdings nicht mit 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
    }
}

Ressourcen

Hinweis: Verwenden Sie nicht die PHPASS-Alternativen, die nicht auf openwall gehostet werden, sie sind verschiedene Projekte !!!

Über BCrypt

Wenn Sie bemerken, gibt jede dieser Bibliotheken eine einzelne Zeichenfolge zurück. Das liegt daran, dass BCrypt intern funktioniert. Und es gibt eine Menge Antworten darauf. Hier ist eine Auswahl, die ich geschrieben habe, die ich hier nicht kopieren / einfügen werde, aber verlinke auf:

Einpacken

Es gibt viele verschiedene Möglichkeiten. Welches du wählst, bleibt dir überlassen. Aber ich würde es tun HÖCHST empfehlen, dass Sie eine der oben genannten Bibliotheken verwenden, um diese für Sie zu behandeln.

Noch einmal, wenn Sie verwenden crypt() direkt, du machst wahrscheinlich etwas falsch. Wenn dein Code verwendet wird hash() (oder md5() oder sha1()) direkt, Sie tun fast definitiv etwas falsch.

Benutze einfach eine Bibliothek ...


273
2018-01-25 15:46



Sie werden eine Menge Informationen erhalten Genug mit den Rainbow Tables: Was Sie über sichere Passwörter wissen müssen oder Portable PHP Passwort Hashing Framework.

Das Ziel ist es, das Passwort mit etwas Langsamem zu hashen, damit jemand, der Ihre Passwort-Datenbank bekommt, stirbt, wenn Sie versuchen, es brutal zu erzwingen (eine Verzögerung von 10 ms, um ein Passwort zu überprüfen, ist nichts für Sie, viel für jemanden, der es brutal erzwingen will). BCrypt ist langsam und kann mit einem Parameter verwendet werden, um zu wählen, wie langsam es ist.


43
2018-01-25 15:48



Sie können einen Einweg-Hash mit bcrypt mit PHP erstellen crypt() Funktion und Weitergabe eines geeigneten Blowfish Salzes. Das wichtigste der ganzen Gleichung ist, dass A) der Algorithmus nicht kompromittiert wurde und B) Sie salzen jedes Passwort richtig. Verwenden Sie kein anwendungsweites Salz; Das öffnet Ihre gesamte Anwendung, um von einem einzigen Satz Rainbow-Tabellen aus anzugreifen.

PHP - Crypt-Funktion


34
2017-10-31 08:25




Edit: 2013.01.15 - Wenn Ihr Server es unterstützt, verwenden Sie martintinckli's Lösung stattdessen.


Jeder will das komplizierter machen als es ist. Die Funktion crypt () erledigt den größten Teil der Arbeit.

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);
}

Beispiel:

$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

Ich weiß, es sollte offensichtlich sein, aber bitte benutze kein Passwort als Passwort.


32
2018-01-11 08:07



Version 5.5 von PHP wird eingebaute Unterstützung für BCrypt, die Funktionen haben password_hash() und password_verify(). Eigentlich sind dies nur Wrapper um die Funktion crypt()und soll es einfacher machen, es richtig zu benutzen. Es sorgt für die Erzeugung eines sicheren Zufallssalzes und liefert gute Standardwerte.

Der einfachste Weg, diese Funktionen zu verwenden, ist:

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

Dieser Code wird das Passwort mit BCrypt (Algorithmus 2y), erzeugt ein zufälliges Salz aus der Zufallsquelle des Betriebssystems und verwendet den Standardkostenparameter (im Moment ist dies 10). Die zweite Zeile prüft, ob das eingegebene Passwort mit einem bereits gespeicherten Hash-Wert übereinstimmt.

Wenn Sie den Kostenparameter ändern möchten, können Sie dies tun, indem Sie den Kostenparameter um 1 erhöhen, die benötigte Zeit für die Berechnung des Hashwerts verdoppelt:

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

Im Gegensatz zu "cost" Parameter, ist es am besten, das wegzulassen "salt" Parameter, weil die Funktion bereits versucht, ein kryptographisch sicheres Salz zu erzeugen.

Für PHP Version 5.3.7 und höher gibt es a Kompatibilitätspaket, von demselben Autor, der das gemacht hat password_hash() Funktion. Für PHP-Versionen vor 5.3.7 gibt es keine Unterstützung für crypt() mit 2yder Unicode-sichere BCrypt-Algorithmus. Man könnte es stattdessen mit ersetzen 2a, das ist die beste Alternative für frühere PHP-Versionen.


24
2018-02-19 14:17



Eine Alternative ist die Verwendung von Scrypt, das speziell von Colin Percival im Jahr 2000 entwickelt wurde sein Papier. Da ist ein scrypt PHP-Erweiterung in PECL. Im Idealfall würde dieser Algorithmus in PHP umgewandelt werden, so dass er für die Funktionen password_ * spezifiziert werden könnte (idealerweise als "PASSWORD_SCRYPT"), aber das ist noch nicht da.


5
2017-12-07 20:56



Aktuelles Denken: Hashes sollten möglichst langsam und nicht so schnell wie möglich sein. Dies unterdrückt Regenbogen-Tisch Anschläge.

Auch verwandt, aber vorsorglich: Ein Angreifer sollte niemals uneingeschränkten Zugriff auf Ihren Anmeldebildschirm haben. Um dies zu verhindern: Richten Sie eine IP-Adressen-Verfolgungstabelle ein, die jeden Treffer zusammen mit dem URI aufzeichnet. Wenn mehr als 5 Anmeldeversuche von derselben IP-Adresse in einem Zeitraum von fünf Minuten kommen, blockieren Sie mit einer Erläuterung. Ein sekundärer Ansatz besteht darin, ein zweistufiges Passwortschema zu verwenden, wie es Banken tun. Eine Sperre für Fehler im zweiten Durchgang erhöht die Sicherheit.

Zusammenfassung: Verlangsamen Sie den Angreifer, indem Sie zeitraubende Hash-Funktionen verwenden. Blockieren Sie auch zu viele Zugriffe auf Ihr Login und fügen Sie eine zweite Passwort-Ebene hinzu.


4
2018-03-25 16:55



Zum OAuth 2 Passwörter:

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

2