Minggu terakhir saya membaca banyak artikel tentang hashing kata sandi dan Blowfish tampaknya menjadi (salah satu) algoritme hashing terbaik saat ini - tetapi bukan itu topik dari pertanyaan ini!
Batas 72 karakter
Blowfish hanya mempertimbangkan 72 karakter pertama dalam kata sandi yang dimasukkan:
<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);
$input = substr($password, 0, 72);
var_dump($input);
var_dump(password_verify($input, $hash));
?>
Outputnya adalah:
string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)
Seperti yang Anda lihat, hanya 72 karakter pertama yang penting. Twitter menggunakan blowfish alias bcrypt untuk menyimpan kata sandi mereka ( https://shouldichangemypassword.com/twitter-hacked.php ) dan coba tebak: ubah kata sandi twitter Anda menjadi kata sandi panjang dengan lebih dari 72 karakter dan Anda dapat masuk ke akun Anda dengan memasukkan hanya 72 karakter pertama.
Blowfish dan Pepper
Ada banyak pendapat berbeda tentang kata sandi "membumbui". Beberapa orang mengatakan itu tidak perlu, karena Anda harus berasumsi bahwa string merica rahasia juga diketahui / diterbitkan sehingga tidak meningkatkan hash. Saya memiliki server database terpisah sehingga sangat mungkin hanya database yang bocor dan bukan lada konstan.
Dalam hal ini (lada tidak bocor) Anda membuat serangan berdasarkan kamus lebih sulit (koreksi saya jika ini tidak benar). Jika benang merica Anda juga bocor: tidak terlalu buruk - Anda masih memiliki garam dan itu terlindungi sebaik hash tanpa merica.
Jadi saya pikir membumbui kata sandi setidaknya bukanlah pilihan yang buruk.
Saran
Saran saya untuk mendapatkan hash Blowfish untuk kata sandi dengan lebih dari 72 karakter (dan merica) adalah:
<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";
// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);
// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);
var_dump(password_verify($input_peppered, $hash));
?>
Ini didasarkan pada pertanyaan ini : password_verify
kembali false
.
Pertanyaan
Apa cara yang lebih aman? Mendapatkan hash SHA-256 terlebih dahulu (yang mengembalikan 64 karakter) atau hanya mempertimbangkan 72 karakter pertama dari kata sandi?
Pro
- Pengguna tidak dapat masuk hanya dengan memasukkan 72 karakter pertama
- Anda dapat menambahkan lada tanpa melebihi batas karakter
- Output dari hash_hmac mungkin akan memiliki lebih banyak entropi daripada kata sandi itu sendiri
- Kata sandi di-hash oleh dua fungsi berbeda
Kontra
- Hanya 64 karakter yang digunakan untuk membuat hash blowfish
Sunting 1: Pertanyaan ini hanya membahas integrasi PHP dari blowfish / bcrypt. Terima kasih atas komentarnya!
Jawaban:
Masalahnya di sini pada dasarnya adalah masalah entropi. Jadi mari kita mulai mencari di sana:
Entropi Per Karakter
Jumlah bit entropi per byte adalah:
Jadi, bagaimana kita bertindak tergantung pada tipe karakter yang kita harapkan.
Masalah Pertama
Masalah pertama dengan kode Anda, adalah langkah hash "pepper" Anda mengeluarkan karakter hex (karena parameter keempat ke
hash_hmac()
tidak disetel).Oleh karena itu, dengan memasukkan lada Anda, Anda secara efektif memotong entropi maksimum yang tersedia untuk kata sandi dengan faktor 2 (dari 576 hingga 288 bit yang mungkin ).
Masalah Kedua
Namun,
sha256
hanya menyediakan256
bit entropi di tempat pertama. Jadi Anda secara efektif memotong kemungkinan 576 bit menjadi 256 bit. Langkah hash Anda * segera *, menurut definisi, kehilangan setidaknya 50% dari kemungkinan entropi dalam kata sandi.Anda dapat menyelesaikan sebagian ini dengan beralih ke
SHA512
, di mana Anda hanya akan mengurangi entropi yang tersedia sekitar 12%. Tapi itu masih perbedaan yang tidak signifikan. 12% itu mengurangi jumlah permutasi dengan faktor1.8e19
. Itu angka yang besar ... Dan itulah faktor yang dikuranginya dengan ...Masalah yang Mendasari
Masalah yang mendasarinya adalah ada tiga jenis kata sandi dengan lebih dari 72 karakter. Dampak sistem gaya ini terhadap mereka akan sangat berbeda:
Catatan: mulai saat ini saya mengasumsikan kami membandingkan dengan sistem lada yang digunakan
SHA512
dengan keluaran mentah (bukan hex).Kata sandi acak dengan entropi tinggi
Ini adalah pengguna Anda yang menggunakan generator kata sandi yang menghasilkan kunci besar untuk kata sandi. Mereka acak (dihasilkan, bukan dipilih manusia), dan memiliki entropi tinggi per karakter. Tipe ini menggunakan byte tinggi (karakter> 127) dan beberapa karakter kontrol.
Untuk grup ini, fungsi hashing Anda akan secara signifikan mengurangi entropi yang tersedia menjadi
bcrypt
.Biar saya katakan lagi. Untuk pengguna yang menggunakan entropi tinggi, sandi panjang, solusi Anda secara signifikan mengurangi kekuatan sandi mereka dengan jumlah yang dapat diukur. (62 bit entropi hilang untuk sandi 72 karakter, dan lebih banyak lagi untuk sandi yang lebih panjang)
Kata sandi acak entropi sedang
Grup ini menggunakan sandi yang berisi simbol umum, tetapi tidak ada byte tinggi atau karakter kontrol. Ini adalah kata sandi Anda yang dapat diketik.
Untuk grup ini, Anda akan membuka sedikit lebih banyak entropi (bukan membuatnya, tetapi mengizinkan lebih banyak entropi untuk masuk ke dalam kata sandi bcrypt). Ketika saya mengatakan sedikit, maksud saya sedikit. Impas terjadi ketika Anda memaksimalkan 512 bit yang dimiliki SHA512. Oleh karena itu, puncaknya ada pada 78 karakter.
Biar saya katakan lagi. Untuk kelas kata sandi ini, Anda hanya dapat menyimpan 6 karakter tambahan sebelum Anda kehabisan entropi.
Kata sandi non-acak entropi rendah
Ini adalah grup yang menggunakan karakter alfanumerik yang mungkin tidak dibuat secara acak. Sesuatu seperti kutipan Alkitab atau semacamnya. Frase ini memiliki sekitar 2,3 bit entropi per karakter.
Untuk grup ini, Anda dapat membuka lebih banyak entropi secara signifikan (bukan membuatnya, tetapi mengizinkan lebih banyak untuk dimasukkan ke dalam input kata sandi bcrypt) dengan melakukan hashing. Titik impas adalah sekitar 223 karakter sebelum Anda kehabisan entropi.
Katakan itu lagi. Untuk kelas kata sandi ini, pra-hashing pasti meningkatkan keamanan secara signifikan.
Kembali Ke Dunia Nyata
Perhitungan entropi semacam ini tidak terlalu penting di dunia nyata. Yang penting adalah menebak entropi. Itulah yang secara langsung mempengaruhi apa yang dapat dilakukan penyerang. Itulah yang ingin Anda maksimalkan.
Meskipun ada sedikit penelitian yang dilakukan untuk menebak entropi, ada beberapa poin yang ingin saya tunjukkan.
Peluang menebak secara acak 72 karakter yang benar berturut-turut sangat rendah. Anda lebih mungkin memenangkan lotre Powerball 21 kali, daripada mengalami tabrakan ini ... Itulah jumlah yang sedang kita bicarakan.
Tapi kita mungkin tidak tersandung pada statistik itu. Dalam kasus frase, kemungkinan 72 karakter pertama menjadi sama jauh lebih tinggi daripada kata sandi acak. Tapi itu masih sangat rendah (Anda lebih cenderung memenangkan lotere Powerball 5 kali, berdasarkan 2,3 bit per karakter).
Praktis
Secara praktis, itu tidak terlalu penting. Peluang seseorang menebak 72 karakter pertama dengan benar, sedangkan yang terakhir membuat perbedaan yang signifikan sangat rendah sehingga tidak perlu dikhawatirkan. Mengapa?
Nah, katakanlah Anda mengambil frase. Jika orang tersebut bisa mendapatkan 72 karakter pertama dengan benar, mereka benar - benar beruntung (tidak mungkin), atau itu adalah frasa yang umum. Jika itu frase umum, satu-satunya variabel adalah berapa panjangnya.
Mari kita ambil contoh. Mari kita ambil kutipan dari Alkitab (hanya karena itu adalah sumber umum dari teks panjang, bukan karena alasan lain):
Itu 180 karakter. Karakter ke-73 adalah
g
yang keduaneighbor's
. Jika Anda sudah menebak sebanyak itu, kemungkinan besar Anda tidak akan berhentinei
, tetapi melanjutkan dengan sisa ayat (karena begitulah kemungkinan besar kata sandi akan digunakan). Oleh karena itu, "hash" Anda tidak menambahkan banyak.BTW: Saya BENAR-BENAR TIDAK menganjurkan penggunaan kutipan Alkitab. Padahal, justru sebaliknya.
Kesimpulan
Anda tidak akan banyak membantu orang yang menggunakan kata sandi panjang dengan melakukan hashing terlebih dahulu. Beberapa grup yang pasti bisa Anda bantu. Beberapa Anda pasti bisa melukai.
Tapi pada akhirnya, tidak ada yang terlalu signifikan. Angka-angka yang kita hadapi hanya WAY terlalu tinggi. Perbedaan entropi tidak akan banyak.
Anda lebih baik membiarkan bcrypt apa adanya. Anda lebih cenderung mengacaukan hashing (secara harfiah, Anda sudah melakukannya, dan Anda bukan yang pertama, atau terakhir membuat kesalahan itu) daripada serangan yang Anda coba cegah akan terjadi.
Berfokuslah untuk mengamankan sisa situs. Dan tambahkan pengukur entropi kata sandi ke kotak kata sandi saat pendaftaran untuk menunjukkan kekuatan kata sandi (dan tunjukkan jika kata sandi terlalu panjang sehingga pengguna mungkin ingin mengubahnya) ...
Itu setidaknya $ 0,02 saya (atau mungkin lebih dari $ 0,02) ...
Sejauh Menggunakan Lada "Rahasia":
Secara harfiah tidak ada penelitian untuk memasukkan satu fungsi hash ke bcrypt. Oleh karena itu, tidak jelas apakah memasukkan hash yang "dibumbui" ke dalam bcrypt akan pernah menyebabkan kerentanan yang tidak diketahui (kami tahu bahwa tindakan tersebut
hash1(hash2($value))
dapat mengekspos kerentanan yang signifikan di sekitar resistensi tabrakan dan serangan preimage).Mengingat Anda sudah mempertimbangkan untuk menyimpan kunci rahasia ("lada"), mengapa tidak menggunakannya dengan cara yang telah dipelajari dan dipahami dengan baik? Mengapa tidak mengenkripsi hash sebelum menyimpannya?
Pada dasarnya, setelah Anda mencirikan kata sandi, masukkan seluruh keluaran hash ke dalam algoritma enkripsi yang kuat. Kemudian simpan hasil yang dienkripsi.
Sekarang, serangan SQL-Injection tidak akan membocorkan sesuatu yang berguna, karena mereka tidak memiliki kunci sandi. Dan jika kuncinya bocor, penyerang tidak lebih baik daripada jika Anda menggunakan hash biasa (yang dapat dibuktikan, sesuatu dengan lada "pra-hash" tidak tersedia).
Catatan: jika Anda memilih untuk melakukan ini, gunakan perpustakaan. Untuk PHP, saya sangat merekomendasikan paket Zend Framework 2
Zend\Crypt
. Ini sebenarnya satu-satunya yang saya rekomendasikan pada saat ini. Ini telah ditinjau dengan kuat, dan itu membuat semua keputusan untuk Anda (yang merupakan hal yang sangat baik) ...Sesuatu seperti:
use Zend\Crypt\BlockCipher; public function createHash($password) { $hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>$this->cost]); $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes')); $blockCipher->setKey($this->key); return $blockCipher->encrypt($hash); } public function verifyHash($password, $hash) { $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes')); $blockCipher->setKey($this->key); $hash = $blockCipher->decrypt($hash); return password_verify($password, $hash); }
Dan itu bermanfaat karena Anda menggunakan semua algoritme dengan cara yang dipahami dengan baik dan dipelajari dengan baik (setidaknya secara relatif). Ingat:
sumber
Membocorkan kata sandi jelas merupakan hal yang baik untuk dilakukan, tetapi mari kita lihat alasannya.
Pertama kita harus menjawab pertanyaan kapan tepatnya merica membantu. Lada hanya melindungi kata sandi, selama tetap rahasia, jadi jika penyerang memiliki akses ke server itu sendiri, itu tidak ada gunanya. Serangan yang jauh lebih mudah adalah injeksi SQL, yang memungkinkan akses baca ke database (ke nilai hash kami), saya menyiapkan demo injeksi SQL untuk menunjukkan betapa mudahnya (klik panah berikutnya untuk menyiapkan memasukkan).
Lalu apa manfaat sebenarnya dari lada? Selama lada tetap dirahasiakan, lada akan melindungi sandi yang lemah dari serangan kamus. Kata sandi
1234
kemudian akan menjadi seperti ini1234-p*deDIUZeRweretWy+.O
. Kata sandi ini tidak hanya lebih panjang, tetapi juga mengandung karakter khusus dan tidak akan pernah menjadi bagian dari kamus mana pun.Sekarang kami dapat memperkirakan kata sandi apa yang akan digunakan pengguna kami, mungkin akan lebih banyak pengguna yang memasukkan kata sandi yang lemah, karena ada pengguna dengan kata sandi antara 64-72 karakter (sebenarnya ini akan sangat jarang).
Poin lainnya adalah kisaran untuk pemaksaan kasar. Fungsi hash sha256 akan mengembalikan output 256 bit atau kombinasi 1.2E77, itu terlalu banyak untuk pemaksaan kasar, bahkan untuk GPU (jika saya menghitung dengan benar, ini akan membutuhkan sekitar 2E61 tahun pada GPU pada tahun 2013). Jadi kita tidak mendapatkan kerugian nyata mengaplikasikan lada. Karena nilai hash tidak sistematis, Anda tidak dapat mempercepat pemaksaan dengan pola umum.
PS Sejauh yang saya tahu, batas 72 karakter khusus untuk algoritma BCrypt itu sendiri. Jawaban terbaik yang saya temukan adalah ini .
PPS Saya pikir contoh Anda cacat, Anda tidak dapat menghasilkan hash dengan panjang kata sandi lengkap, dan memverifikasinya dengan yang terpotong. Anda mungkin bermaksud menerapkan lada dengan cara yang sama untuk menghasilkan hash dan untuk verifikasi hash.
sumber
true
. Tentang itulah pertanyaan ini. Lihat sendiri: viper-7.com/RLKFnBBcrypt menggunakan algoritma yang didasarkan pada algoritma penyiapan kunci Blowfish yang mahal.
Batas kata sandi 56 byte yang direkomendasikan (termasuk byte terminasi nol) untuk bcrypt berhubungan dengan batas 448 bit dari kunci Blowfish. Setiap byte di luar batas itu tidak sepenuhnya tercampur ke dalam hash yang dihasilkan. Oleh karena itu, batas absolut 72 byte pada kata sandi bcrypt kurang relevan, ketika Anda mempertimbangkan efek sebenarnya pada hash yang dihasilkan oleh byte tersebut.
Jika menurut Anda pengguna Anda biasanya akan memilih kata sandi yang panjangnya lebih dari 55 byte, ingatlah Anda selalu dapat meningkatkan putaran peregangan kata sandi, untuk meningkatkan keamanan dalam kasus pelanggaran tabel kata sandi (meskipun ini harus banyak dibandingkan dengan menambahkan tambahan karakter). Jika hak akses pengguna sangat penting sehingga pengguna biasanya memerlukan kata sandi yang sangat panjang, maka masa berlaku kata sandi juga harus singkat, seperti 2 minggu. Ini berarti bahwa kata sandi jauh lebih kecil kemungkinannya untuk tetap valid sementara peretas menginvestasikan sumber dayanya untuk mengalahkan faktor kerja yang terlibat dalam pengujian setiap kata sandi percobaan untuk melihat apakah itu akan menghasilkan hash yang cocok.
Tentu saja, jika tabel kata sandi tidak dilanggar, kami hanya mengizinkan peretas, paling banyak, sepuluh upaya untuk menebak kata sandi 55 byte pengguna, sebelum mengunci akun pengguna;)
Jika Anda memutuskan untuk melakukan pra-hash kata sandi yang lebih panjang dari 55 byte, maka Anda harus menggunakan SHA-384, karena memiliki keluaran terbesar tanpa melewati batas.
sumber