Apa jenis / panjang kolom yang harus saya gunakan untuk menyimpan kata sandi hash Bcrypt dalam Database?

318

Saya ingin menyimpan kata sandi hash (menggunakan BCrypt) dalam database. Apa yang akan menjadi tipe yang baik untuk ini, dan mana yang akan menjadi panjang yang benar? Apakah kata sandi hash dengan BCrypt selalu sama panjang?

EDIT

Contoh hash:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

Setelah membuat beberapa kata sandi, tampaknya BCrypt selalu menghasilkan hash 60 karakter.

EDIT 2

Maaf karena tidak menyebutkan implementasinya. Saya menggunakan jBCrypt .

metode helpermet
sumber
Juga lihat kerangka hashing kata sandi PHP (PHPass) Openwall. Ini portabel dan mengeras terhadap sejumlah serangan umum pada kata sandi pengguna. Orang yang menulis kerangka kerja (SolarDesigner) adalah orang yang sama yang menulis John The Ripper dan duduk sebagai juri di Kompetisi Sandi Hashing . Jadi dia tahu satu atau dua hal tentang serangan pada kata sandi.
jww
1
Jika ada orang yang mencari solusi untuk scrypt : jawaban Gumbo juga berlaku untuk scrypt. Saya pribadi menerapkan BINARY (64) di MySQL dan memungkinkan saya untuk menguji kesetaraan byte di bawah Python nanti.
Philippe Hebert

Jawaban:

369

Format crypt modular untuk bcrypt terdiri dari

  • $2$, $2a$atau $2y$mengidentifikasi algoritma dan format hashing
  • nilai dua digit yang menunjukkan parameter biaya, diikuti oleh $
  • 53 karakter nilai dasar-64-encoded (mereka menggunakan alfabet ., /, 0- 9, A- Z, a- zyang berbeda dengan Basis standar 64 Encoding abjad) yang terdiri dari:
    • 22 karakter garam (secara efektif hanya 128 bit dari 132 bit yang diterjemahkan)
    • 31 karakter dari output terenkripsi (efektif hanya 184 bit dari 186 bit yang diterjemahkan)

Jadi total panjangnya masing-masing adalah 59 atau 60 byte.

Saat Anda menggunakan format 2a, Anda akan membutuhkan 60 byte. Dan karenanya untuk MySQL saya akan merekomendasikan untuk menggunakan CHAR(60) BINARYatauBINARY(60) (lihat The _bin dan Binary Collations untuk informasi tentang perbedaannya).

CHARtidak biner aman dan kesetaraan tidak hanya bergantung pada nilai byte tetapi pada pemeriksaan yang sebenarnya; dalam kasus terburuk Adiperlakukan sama dengan a. Lihat The _binand binaryCollations untuk informasi lebih lanjut.

Gumbo
sumber
28
Sadarilah - menyimpan sebagai biner (60) dapat menyebabkan perilaku tak terduga untuk persamaan string (antara lain). Dalam .NET ini dapat diatasi dengan menggunakan String.Equals (dariDataBaseBinary60string, typicalishString, StringComparison.InvariantCulture)
JHubbard80
8
Jika Anda mendefinisikan kolom sebagai CHAR (60) CHARACTER SET latin1 COLLATE latin1_bin, Anda sekarang mendapatkan keuntungan dari perbandingan string yang akurat tanpa memerlukan kolom biner.
Ben
2
@AndreFigueiredo SQL_Latin1_General_CP1_CS_AStidak dikenal di MySQL. Yang diketahui adalah latin1_general_cs.
Gumbo
1
Aku akan senang untuk memiliki definisi sini untuk apa 2, 2adan 2yrata-rata untuk algoritma hashing dan format. Saya tidak dapat menemukan jawaban yang mudah dengan beberapa pencarian.
jocull
2
@Neon Masalahnya adalah bahwa Anda dapat membandingkan hash yang berbeda untuk menjadi sama. Jika Anda secara eksplisit menentukan bahwa itu adalah kolom biner (atau VARCHAR dengan susunan yang benar), Anda tidak menjalankan risiko, di tempat lain, mengubah beberapa pengaturan yang menjadikannya perbandingan case-insensitive. Ini juga membuat maksud Anda lebih jelas, yang umumnya merupakan hal yang baik - Anda menyimpan data biner; Anda harus menyimpannya sebagai data biner.
Dana Gugatan Monica
52

Hash Bcrypt dapat disimpan dalam BINARY(40)kolom.

BINARY(60), seperti yang disarankan oleh jawaban lain, adalah pilihan termudah dan paling alami, tetapi jika Anda ingin memaksimalkan efisiensi penyimpanan, Anda dapat menghemat 20 byte dengan mendekonstruksi hash tanpa kehilangan. Saya telah mendokumentasikan ini lebih menyeluruh di GitHub: https://github.com/ademarre/binary-mcf

Bcrypt hash mengikuti struktur yang disebut sebagai modular crypt format (MCF). Binary MCF (BMCF) menerjemahkan kode hash ini menjadi struktur biner yang lebih kompak. Dalam kasus Bcrypt, hash biner yang dihasilkan adalah 40 byte.

Gumbo melakukan pekerjaan yang baik untuk menjelaskan empat komponen hash Bcrypt MCF:

$<id>$<cost>$<salt><digest>

Penguraian ke BMCF seperti ini:

  1. $<id>$ dapat direpresentasikan dalam 3 bit.
  2. <cost>$, 04-31, dapat direpresentasikan dalam 5 bit. Masukkan ini bersama-sama selama 1 byte.
  3. Garam 22 karakter adalah representasi basis-64 (non-standar) dari 128 bit. Dekode basis-64 menghasilkan 16 byte.
  4. Intisari 31-karakter dapat base-64 diterjemahkan ke 23 byte.
  5. Gabungkan semuanya selama 40 byte: 1 + 16 + 23

Anda dapat membaca lebih lanjut di tautan di atas, atau memeriksa implementasi PHP saya , juga di GitHub.

Andre D
sumber
49
Biaya bidang yang lebih panjang: 20 byte kali bahkan sejuta + catatan: 20MB, begitu Anda mencapai sejuta catatan +. Biaya penerapan panjang bidang yang tidak tepat dengan tepat, di bidang keamanan & rekayasa yang sangat kompleks: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Lihat Penawaran Anda dapat melakukan perhitungan.
Kzqai
6
@ Kzqai, seperti yang saya katakan, kolom 60-byte yang lebih besar adalah pilihan paling alami, tetapi seberapa agresif untuk mengejar efisiensi penyimpanan tergantung pada proyek. Sebagai contoh, itu umum untuk mencoba menyesuaikan seluruh database dalam memori, dan 20 MB di sini dan 20 lainnya di sana dapat bertambah dengan cepat di lingkungan yang dibatasi memori.
Andre D
10
Contoh Anda mengumpankan poin saya. --- Jika Anda ingin memasukkan basis data ke dalam memori, optimalkan setiap kolom lainnya sebelum menyentuh kolom penyimpanan bcrypt. --- Jika Anda telah mengoptimalkan setiap kolom lainnya hingga derajat yang gila, dan hanya kolom hash bcrypt yang tersisa, dapatkan memori lain hanya untuk bcrypt. --- Jika Anda telah melakukan kedua hal di atas ... ... berhenti, Anda belum mengoptimalkan setiap kolom buah menggantung lainnya, dan Anda akan mengacaukan dengan sistem keamanan kriptografi teruji yang berfungsi, dan ganti dengan sistem yang dikembangkan di rumah yang lebih rumit dengan kemungkinan kegagalan implementasi.
Kzqai
11
@Kzqai Tidak ada risiko melemahkan keamanan perpustakaan Bcrypt Anda di sini. Ini adalah penyandian data yang dibatalkan saat pengambilan dari penyimpanan sebelum pemeriksaan kata sandi. Ini bukan wilayah "jangan putar crypto Anda sendiri".
Andre D
1
Penjelasan yang bagus. :) Meskipun penjelasan Anda memberi ide bagus, saya hanya ingin pergi dengan 60 karakter, bahkan 100 karakter, hanya untuk berada di sisi yang aman. Debat yang bagus juga @Kzqai dan AndreD
Naveen Kumar V
23

Jika Anda menggunakan PHP password_hash()dengan PASSWORD_DEFAULTalgoritme untuk menghasilkan hash bcrypt (yang saya asumsikan adalah sebagian besar orang yang membaca pertanyaan ini) pastikan untuk diingat bahwa di masa depan password_hash()mungkin menggunakan algoritma yang berbeda sebagai default dan oleh karena itu ini bisa mempengaruhi panjang hash (tetapi mungkin tidak harus lebih lama).

Dari halaman manual:

Perhatikan bahwa konstanta ini dirancang untuk berubah seiring waktu karena algoritma baru dan lebih kuat ditambahkan ke PHP. Karena alasan itu, panjang hasil menggunakan pengenal ini dapat berubah seiring waktu. Oleh karena itu, disarankan untuk menyimpan hasilnya dalam kolom basis data yang dapat diperluas melebihi 60 karakter (255 karakter akan menjadi pilihan yang baik).

Menggunakan bcrypt, bahkan jika Anda memiliki 1 miliar pengguna (yaitu Anda saat ini bersaing dengan facebook) untuk menyimpan hash kata sandi 255 byte, data itu hanya ~ 255 GB - seukuran hard drive SSD yang lebih kecil. Sangat tidak mungkin menyimpan hash kata sandi akan menjadi hambatan dalam aplikasi Anda. Namun jika ruang penyimpanan benar - benar menjadi masalah karena beberapa alasan, Anda dapat menggunakan PASSWORD_BCRYPTuntuk memaksa password_hash()menggunakan bcrypt, bahkan jika itu bukan default. Pastikan untuk tetap mendapat informasi tentang kerentanan apa pun yang ditemukan di bcrypt dan tinjau catatan rilis setiap kali versi PHP baru dirilis. Jika algoritma default diubah, alangkah baiknya untuk meninjau alasannya dan membuat keputusan berdasarkan informasi apakah akan menggunakan algoritma baru atau tidak.

Mike
sumber
20

Saya tidak berpikir bahwa ada trik rapi yang dapat Anda lakukan menyimpan ini seperti yang dapat Anda lakukan misalnya dengan hash MD5.

Saya pikir taruhan terbaik Anda adalah menyimpannya karena CHAR(60)selalu 60 karakter

James C
sumber
Meskipun, dokumentasi PHP mencatat bahwa kolom harus dapat menampung lebih banyak data, untuk rilis mendatang ...
Julian F. Weinert
16
Tidak ada alasan untuk piring emas. Jika perangkat lunak yang Anda gunakan membutuhkan enam puluh byte, maka alokasikan enam puluh byte. Jika ada rilis mendatang untuk perangkat lunak Anda yang mengubah ini, maka Anda dapat khawatir tentang hal itu ketika rilis itu terjadi. Anda seharusnya tidak secara otomatis menginstal pembaruan yang mengubah fungsi.
Tyler Crompton