Pertanyaan Bagaimana Anda menggunakan bcrypt untuk hashing passwords di PHP?


Sesekali saya mendengar saran "Gunakan bcrypt untuk menyimpan kata sandi dalam PHP, aturan bcrypt".

Tapi apa itu? bcrypt? PHP tidak menawarkan fungsi seperti itu, Wikipedia mengoceh tentang utilitas enkripsi file dan pencarian Web hanya mengungkapkan beberapa implementasi Blowfish dalam bahasa yang berbeda. Sekarang Blowfish juga tersedia di PHP via mcrypt, tapi bagaimana itu membantu dengan menyimpan kata sandi? Blowfish adalah cipher tujuan umum, berfungsi dua cara. Jika bisa dienkripsi, itu bisa didekripsi. Kata sandi membutuhkan fungsi hashing satu arah.

Apa penjelasannya?


1145
2018-01-25 15:34


asal


Jawaban:


bcrypt adalah algoritma hashing yang dapat diskalakan dengan perangkat keras (melalui sejumlah putaran yang dapat dikonfigurasi). Kelambatan dan beberapa putaran memastikan bahwa penyerang harus mengerahkan dana besar dan perangkat keras untuk dapat memecahkan kata sandi Anda. Tambahkan ke kata sandi itu garam (bcrypt MEMBUTUHKAN garam-garam) dan Anda dapat yakin bahwa suatu serangan hampir tidak mungkin dilakukan tanpa jumlah dana atau perangkat keras yang menggelikan.

bcrypt menggunakan Eksblowfish algoritma untuk hash password. Sedangkan fase enkripsi Eksblowfish dan Blowfish persis sama, fase jadwal utama Eksblowfish memastikan bahwa keadaan berikutnya bergantung pada garam dan kunci (kata sandi pengguna), dan tidak ada negara yang dapat diprediksi tanpa sepengetahuan keduanya. Karena perbedaan utama ini, bcrypt adalah algoritma hashing satu arah. Anda tidak dapat mengambil kata sandi teks biasa tanpa sudah mengetahui garam, ronde dan kunci (kata sandi). [Sumber]

Cara menggunakan bcrypt:

Menggunakan PHP> = 5.5-DEV

Fungsi hashing kata sandi sekarang telah dibangun langsung ke PHP> = 5.5. Anda sekarang dapat menggunakan password_hash() untuk membuat bcrypt hash dari kata sandi apa pun:

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

Untuk memverifikasi kata sandi yang diberikan pengguna terhadap hash yang ada, Anda dapat menggunakan password_verify() Dengan demikian:

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

Menggunakan PHP> = 5.3.7, <5.5-DEV (juga RedHat PHP> = 5.3.3)

Ada sebuah pustaka kompatibilitas di GitHub dibuat berdasarkan kode sumber dari fungsi di atas yang aslinya ditulis dalam C, yang menyediakan fungsi yang sama. Setelah perpustakaan kompatibilitas diinstal, penggunaannya sama seperti di atas (minus notasi larik array jika Anda masih di cabang 5.3.x).

Menggunakan PHP <5.3.7 (TIDAK DIGUNAKAN)

Kamu dapat memakai crypt() berfungsi untuk menghasilkan bcrypt hash string input. Kelas ini dapat secara otomatis menghasilkan garam dan memverifikasi hash yang ada terhadap masukan. Jika Anda menggunakan versi PHP lebih tinggi atau sama dengan 5.3.7, sangat disarankan Anda menggunakan fungsi built-in atau pustaka compat. Alternatif ini disediakan hanya untuk tujuan historis.

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

Anda dapat menggunakan kode ini seperti ini:

$bcrypt = new Bcrypt(15);

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

Atau, Anda juga dapat menggunakan Kerangka Hashing PHP Portable.


973
2018-06-12 19:23



Jadi, Anda ingin menggunakan bcrypt? Luar biasa! Namun, seperti area kriptografi lainnya, Anda tidak seharusnya melakukannya sendiri. Jika Anda perlu khawatir tentang apa pun seperti mengelola kunci, atau menyimpan garam atau menghasilkan angka acak, Anda salah melakukannya.

Alasannya sederhana: itu sangat mudah mengacaukan bcrypt. Bahkan, jika Anda melihat hampir setiap bagian kode di halaman ini, Anda akan melihat bahwa itu melanggar setidaknya satu dari masalah umum ini.

Hadapi itu, Kriptografi sulit.

Biarkan untuk para ahli. Biarkan untuk orang yang pekerjaannya adalah memelihara perpustakaan ini. Jika Anda perlu membuat keputusan, Anda melakukannya dengan salah.

Sebagai gantinya, cukup gunakan perpustakaan. Beberapa ada tergantung pada kebutuhan Anda.

Perpustakaan

Berikut ini adalah uraian beberapa API yang lebih umum.

PHP 5.5 API - (Tersedia untuk 5.3.7+)

Mulai dari PHP 5.5, API baru untuk hashing password sedang diperkenalkan. Ada juga perpustakaan kompatibilitas shim yang dikelola (oleh saya) untuk 5.3.7+. Ini memiliki manfaat sebagai peer-review dan sederhana untuk menggunakan implementasi.

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

Sungguh, ini bertujuan untuk menjadi sangat sederhana.

Sumber daya:

Zend \ Crypt \ Password \ Bcrypt (5.3.2+)

Ini adalah API lain yang mirip dengan PHP 5.5 satu, dan melakukan tujuan yang sama.

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

Sumber daya:

PasswordLib

Ini adalah pendekatan yang sedikit berbeda untuk hashing kata sandi. Daripada hanya mendukung bcrypt, PasswordLib mendukung sejumlah besar algoritma hashing. Ini terutama berguna dalam konteks di mana Anda perlu mendukung kompatibilitas dengan sistem warisan dan berbeda yang mungkin berada di luar kendali Anda. Ini mendukung sejumlah besar algoritma hashing. Dan didukung 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
    }
}

Referensi:

  • Kode Sumber / Dokumentasi: GitHub

PHPASS

Ini adalah lapisan yang mendukung bcrypt, tetapi juga mendukung algoritma yang cukup kuat yang berguna jika Anda tidak memiliki akses ke PHP> = 5.3.2 ... Ini sebenarnya mendukung PHP 3.0+ (meskipun tidak dengan 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
    }
}

Sumber daya

catatan: Jangan gunakan PHPASS alternatif yang tidak di-host di openwall, mereka adalah proyek yang berbeda !!!

Tentang BCrypt

Jika Anda perhatikan, semua pustaka ini mengembalikan satu string. Itu karena cara kerja BCrypt secara internal. Dan ada TON jawaban tentang itu. Berikut ini adalah pilihan yang saya tulis, yang tidak akan saya salin / tempel di sini, tetapi tautan ke:

Bungkus

Ada banyak pilihan berbeda. Yang Anda pilih terserah Anda. Namun, saya akan melakukannya SANGAT sarankan agar Anda menggunakan salah satu pustaka di atas untuk menangani ini untuk Anda.

Sekali lagi, jika Anda menggunakan crypt() secara langsung, Anda mungkin melakukan sesuatu yang salah. Jika kode Anda sedang digunakan hash() (atau md5() atau sha1()) Secara langsung, Anda hampir pasti melakukan sesuatu yang salah.

Cukup gunakan perpustakaan ...


273
2018-01-25 15:46



Anda akan mendapatkan banyak informasi Cukup Dengan The Rainbow Tables: Apa yang Perlu Anda Ketahui Tentang Skema Kata Sandi Aman atau Kerangka sandi hashing PHP portabel.

Tujuannya adalah untuk meng-hash kata sandi dengan sesuatu yang lambat, sehingga seseorang yang mendapatkan basis data kata sandi Anda akan mati mencoba untuk membesarkannya (penundaan 10 mdetik untuk memeriksa kata sandi tidak berarti apa-apa bagi Anda, banyak bagi seseorang yang mencoba memaksanya). Bcrypt lambat dan dapat digunakan dengan parameter untuk memilih seberapa lambatnya.


43
2018-01-25 15:48



Anda dapat membuat hash satu arah dengan bcrypt menggunakan PHP crypt() berfungsi dan melewati garam Blowfish yang tepat. Yang terpenting dari keseluruhan persamaan adalah bahwa A) algoritma belum dikompromikan dan B) Anda benar garam setiap kata sandi. Jangan gunakan garam di seluruh aplikasi; yang membuka seluruh aplikasi Anda untuk menyerang dari satu set tabel Rainbow.

PHP - Fungsi Crypt


34
2017-10-31 08:25




Edit: 2013.01.15 - Jika server Anda akan mendukungnya, gunakan solusi martinstoeckli sebagai gantinya.


Semua orang ingin membuat ini lebih rumit daripada itu. Fungsi crypt () melakukan sebagian besar pekerjaan.

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

Contoh:

$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

Saya tahu itu harus jelas, tapi tolong jangan gunakan 'kata sandi' sebagai kata sandi Anda.


32
2018-01-11 08:07



Versi 5.5 PHP akan memiliki dukungan built-in untuk BCrypt, fungsi-fungsinya password_hash() dan password_verify(). Sebenarnya ini hanyalah pembungkus di sekitar fungsi crypt(), dan akan membuatnya lebih mudah untuk menggunakannya dengan benar. Ini mengurus generasi garam acak yang aman, dan memberikan nilai default yang baik.

Cara termudah untuk menggunakan fungsi ini adalah:

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

Kode ini akan hash kata sandi dengan BCrypt (algoritma 2y), menghasilkan garam acak dari sumber acak OS, dan menggunakan parameter biaya default (saat ini adalah 10). Cek baris kedua, jika kata sandi yang dimasukkan pengguna cocok dengan nilai hash yang sudah disimpan.

Jika Anda ingin mengubah parameter biaya, Anda dapat melakukannya seperti ini, meningkatkan parameter biaya sebesar 1, menggandakan waktu yang diperlukan untuk menghitung nilai hash:

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

Berbeda dengan "cost" parameter, yang terbaik adalah menghilangkan "salt" parameter, karena fungsi sudah melakukan yang terbaik untuk membuat garam yang aman secara kriptografi.

Untuk versi PHP 5.3.7 dan yang lebih baru, ada a paket kompatibilitas, dari penulis yang sama yang membuat password_hash() fungsi. Untuk versi PHP sebelum 5.3.7 tidak ada dukungan untuk crypt() dengan 2y, algoritma BCrypt aman unicode. Orang bisa menggantikannya dengan 2a, yang merupakan alternatif terbaik untuk versi PHP sebelumnya.


24
2018-02-19 14:17



Alternatifnya adalah dengan menggunakan scrypt, yang dirancang khusus agar lebih unggul daripada bcrypt oleh Colin Percival di makalahnya. Ada sebuah ekstensi PHP scrypt dalam PECL. Idealnya algoritma ini akan diluncurkan ke PHP sehingga bisa ditentukan untuk fungsi kata sandi_ * (idealnya sebagai "PASSWORD_SCRYPT"), tetapi itu belum ada.


5
2017-12-07 20:56



Pemikiran saat ini: hash harus menjadi yang paling lambat tersedia, bukan yang tercepat. Ini menekan meja pelangi serangan.

Juga terkait, tetapi pencegahan: Seorang penyerang tidak boleh memiliki akses tanpa batas ke layar login Anda. Untuk mencegah hal itu: Siapkan tabel pelacakan alamat IP yang mencatat setiap klik bersama dengan URI. Jika lebih dari 5 upaya masuk berasal dari alamat IP yang sama dalam periode lima menit, cekal dengan penjelasan. Pendekatan sekunder adalah memiliki skema kata sandi dua tingkat, seperti yang dilakukan oleh bank. Menempatkan lock-out untuk kegagalan pada lintasan kedua meningkatkan keamanan.

Ringkasan: memperlambat penyerang dengan menggunakan fungsi hash yang memakan waktu. Juga, blokir terlalu banyak akses ke login Anda, dan tambahkan tier kata sandi kedua.


4
2018-03-25 16:55



Untuk OAuth 2 kata sandi:

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

2