it-swarm.com.de

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

Hin und wieder höre ich den Rat "Verwende bcrypt zum Speichern von Passwörtern in PHP, Verschlüsselungsregeln".

Aber was ist bcrypt? PHP bietet keine solchen Funktionen an, Wikipedia plappert über ein Dienstprogramm zur Dateiverschlüsselung und die Websuche enthüllt nur einige Implementierungen von Blowfish in verschiedenen Sprachen. Jetzt ist Blowfish auch in PHP über mcrypt verfügbar, aber wie hilft das beim Speichern von Passwörtern? Blowfish ist eine Universal-Chiffre, die auf zwei Arten funktioniert. Wenn es verschlüsselt werden konnte, kann es entschlüsselt werden. Passwörter benötigen eine One-Way-Hashing-Funktion.

Was ist die Erklärung?

1219
Vilx-

bcrypt ist ein mit Hardware skalierbarer Hashing-Algorithmus (über eine konfigurierbare Anzahl von Runden). Seine Langsamkeit und mehrere Runden sorgen dafür, dass ein Angreifer massive Mittel und Hardware einsetzen muss, um Ihre Passwörter knacken zu können. Wenn Sie dieses Kennwort mit Salze (bcrypt REQUIRES Salze) addieren, können Sie sicher sein, dass ein Angriff praktisch nicht durchführbar ist, ohne eine lächerliche Menge an Geld oder Hardware.

bcrypt verwendet den Eksblowfish Algorithmus, um Passwörter zu hashen. Während die Verschlüsselungsphase von Eksblowfish und Blowfish genau gleich ist, ist die Hauptzeitplanphase von Eksblowfish stellt sicher, dass jeder nachfolgende Status sowohl von Salt als auch von Key (Benutzerpasswort) abhängt und kein Status ohne das Wissen von beiden vorberechnet werden kann. Aufgrund dieses Hauptunterschieds ist bcrypt ein Einweg-Hashing-Algorithmus. Sie können das Klartext-Passwort nicht abrufen, ohne das Salt, die Runden bereits zu kennen nd Schlüssel ( Passwort). [ Quelle ]

So verwenden Sie bcrypt:

Mit PHP> = 5.5-DEV

Passwort-Hashing-Funktionen wurden jetzt direkt in PHP> = 5.5 integriert . Sie können jetzt password_hash() verwenden, um einen bcrypt -Hash eines beliebigen Passworts zu erstellen:

<?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 mit einem vorhandenen Hash zu verifizieren, können Sie password_verify() als solches verwenden:

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

Es gibt eine Kompatibilitätsbibliothek on GitHub , die auf dem Quellcode der obigen ursprünglich in C geschriebenen Funktionen basiert und die gleiche Funktionalität bietet. Sobald die Kompatibilitätsbibliothek installiert ist, ist die Verwendung dieselbe wie oben (abzüglich der Kurzschreibweise für Arrays, wenn Sie sich noch in der 5.3.x-Verzweigung befinden).

Verwenden von PHP <5.3.7 (DEPRECATED)

Sie können die Funktion crypt() verwenden, um bcrypt-Hashes von Eingabezeichenfolgen zu generieren. Diese Klasse kann automatisch Salze generieren und vorhandene Hashes anhand einer Eingabe überprüfen. Wenn Sie eine Version von PHP höher oder gleich 5.3.7 verwenden, wird dringend empfohlen, die integrierte Funktion oder die kompatible 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 das Portable PHP Hashing Framework verwenden.

1037
Andrew Moore

Sie möchten also bcrypt verwenden? Genial! Wie in anderen Bereichen der Kryptografie 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, machen Sie es falsch.

Der Grund ist einfach: Es ist so einfach, bcrypt zu vermasseln . Wenn Sie sich fast jeden Code auf dieser Seite ansehen, werden Sie feststellen, dass er gegen mindestens eines dieser allgemeinen Probleme verstößt.

Seien Sie ehrlich, Kryptographie ist schwer.

Überlassen Sie es den Experten. Überlassen Sie es den Leuten, die diese Bibliotheken unterhalten sollen. Wenn Sie eine Entscheidung treffen müssen, machen Sie es falsch.

Verwenden Sie stattdessen einfach eine Bibliothek. Je nach Ihren Anforderungen gibt es mehrere.

Bibliotheken

Hier finden Sie eine Aufschlüsselung einiger der am häufigsten verwendeten APIs.

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

Ab PHP 5.5 wird eine neue API für das Hashing von Passwörtern eingeführt. Es gibt auch eine Shim-Kompatibilitätsbibliothek (von mir) für 5.3.7+. Dies hat den Vorteil, dass es von Fachleuten begutachtet wird und die Implementierung simple verwendet wird.

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 soll extrem einfach sein.

Ressourcen:

Zend\Crypt\Password\Bcrypt (5.3.2+)

Dies ist eine weitere API, die der PHP 5.5 ähnelt 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:

PasswordLib

Dies ist ein etwas anderer Ansatz zum Hashing von Passwörtern. Anstatt nur bcrypt zu unterstützen, unterstützt PasswordLib eine Vielzahl von Hashing-Algorithmen. Dies ist hauptsächlich in Situationen nützlich, in denen Sie die Kompatibilität mit älteren und unterschiedlichen Systemen unterstützen müssen, auf die Sie möglicherweise keinen Einfluss haben. Es unterstützt eine große Anzahl von Hashing-Algorithmen. 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 eine Ebene, die bcrypt unterstützt, aber auch einen ziemlich starken Algorithmus, der nützlich ist, wenn Sie keinen Zugriff auf PHP> = 5.3.2 haben ... Es unterstützt tatsächlich PHP 3.0+ (obwohl 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 keine PHPASS-Alternativen, die nicht auf openwall gehostet werden, es handelt sich um unterschiedliche Projekte !!!

Über BCrypt

Wenn Sie bemerken, gibt jede dieser Bibliotheken eine einzelne Zeichenfolge zurück. Das liegt daran, wie BCrypt intern arbeitet. Und es gibt eine Menge Antworten dazu. Hier ist eine Auswahl, die ich geschrieben habe und die ich hier nicht kopieren/einfügen, sondern verlinken möchte:

Einpacken

Es gibt viele verschiedene Möglichkeiten. Die Wahl liegt bei Ihnen. Ich würde jedoch DRINGEND empfehlen, dass Sie eine der oben genannten Bibliotheken verwenden, um dies für Sie zu handhaben.

Wenn Sie crypt() direkt verwenden, machen Sie wahrscheinlich etwas falsch. Wenn Ihr Code direkt hash() (oder md5() oder sha1()) verwendet, machen Sie mit ziemlicher Sicherheit etwas falsch.

Benutze einfach eine Bibliothek ...

289
ircmaxell

Sie erhalten viele Informationen in Genug mit den Rainbow-Tabellen: Was Sie über sichere Passwortschemata wissen müssen oder Portable PHP Passwort-Hashing-Framework.

Das Ziel ist es, das Passwort mit etwas Langsamem zu hacken, sodass jemand, der Ihre Passwortdatenbank abruft, beim Versuch, sie zu erzwingen, abstürzt (eine Verzögerung von 10 ms zum Überprüfen eines Passworts ist nichts für Sie, viel für jemanden, der versucht, sie zu erzwingen). Bcrypt ist langsam und kann mit einem Parameter verwendet werden, um zu bestimmen, wie langsam es ist.

46
Arkh

Sie können einen One-Way-Hash mit bcrypt erstellen, indem Sie die Funktion crypt() von PHP verwenden und ein geeignetes Blowfish-Salt übergeben. Das Wichtigste an der ganzen Gleichung ist, dass A) der Algorithmus nicht kompromittiert wurde und B) Sie jedes Passwort richtig salzen . Verwenden Sie kein anwendungsweites Salz. Das öffnet Ihre gesamte Anwendung für Angriffe von einer einzigen Gruppe von Rainbow-Tabellen aus.

PHP - Crypt Funktion

35
coreyward

Edit: 2013.01.15 - Wenn Ihr Server dies unterstützt, verwenden Sie stattdessen martinstoecklis Lösung .


Jeder möchte das komplizierter machen als es ist. Die crypt () - Funktion 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ß, dass es offensichtlich sein sollte, aber bitte verwenden Sie nicht "Passwort" als Ihr Passwort.

33
Jon Hulka

Version 5.5 von PHP wird BCrypt, die Funktionen password_hash() und password_verify() unterstützen. Tatsächlich handelt es sich nur um Wrapper um die Funktion crypt() und soll die korrekte Verwendung erleichtern. Es sorgt für die Erzeugung eines sicheren zufälligen Salzes und liefert gute Standardwerte.

Der einfachste Weg, diese Funktionen zu nutzen, ist:

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

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

Wenn Sie den Kostenparameter ändern möchten, können Sie dies folgendermaßen tun, indem Sie den Kostenparameter um 1 erhöhen und die für die Berechnung des Hashwerts erforderliche Zeit verdoppeln:

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

Im Gegensatz zum Parameter "cost" sollte der Parameter "salt" weggelassen werden, da die Funktion bereits ihr Bestes tut, um ein kryptografisch sicheres Salt zu erstellen.

Für PHP Version 5.3.7 und höher gibt es ein Kompatibilitätspaket vom selben Autor, der die Funktion password_hash() erstellt hat. Für PHP Versionen vor 5.3.7 gibt es keine Unterstützung für crypt() mit 2y, dem Unicode-sicheren BCrypt-Algorithmus. Man könnte es stattdessen durch 2a ersetzen, was die beste Alternative für frühere PHP Versionen ist.

27
martinstoeckli

Eine Alternative ist die Verwendung von Scrypt, das speziell von Colin Percival in seinem Artikel entwickelt wurde, um bcrypt überlegen zu sein. Es gibt eine scrypt PHP -Erweiterung in PECL . Idealerweise würde dieser Algorithmus in PHP gerollt, damit er für die password_ * -Funktionen angegeben werden kann (idealerweise als "PASSWORD_SCRYPT"), aber das ist noch nicht vorhanden.

6
Synchro

Aktuelle Überlegungen: Hashes sollten die langsamsten verfügbaren und nicht die schnellsten sein. Dies unterdrückt Rainbow-Tabelle Angriffe.

Ebenfalls verwandt, aber vorsorglich: Ein Angreifer sollte niemals uneingeschränkten Zugriff auf Ihren Anmeldebildschirm haben. So verhindern Sie dies: Richten Sie eine IP-Adressverfolgungstabelle ein, die jeden Treffer zusammen mit der URI aufzeichnet. Wenn in einem Zeitraum von fünf Minuten mehr als fünf Anmeldeversuche von derselben IP-Adresse ausgehen, blockieren Sie diese mit einer Erklärung. Ein zweiter Ansatz besteht darin, ein zweistufiges Kennwortschema zu verwenden, wie dies bei Banken der Fall ist. Das Sperren von Fehlern im zweiten Durchgang erhöht die Sicherheit.

Zusammenfassung: Verlangsamen Sie den Angreifer mit zeitaufwändigen Hash-Funktionen. Sperren Sie außerdem zu viele Zugriffe auf Ihr Login und fügen Sie eine zweite Passwortebene hinzu.

6
FYA

Für OAuth 2 Passwörter:

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