it-swarm-id.com

HMAC - Mengapa tidak HMAC untuk penyimpanan kata sandi?

Nota bene: Saya sadar bahwa jawaban yang baik untuk mengamankan penyimpanan kata sandi adalah --- scrypt atau bcrypt . Pertanyaan ini bukan untuk implementasi dalam perangkat lunak aktual, ini untuk pemahaman saya sendiri.

Katakanlah Joe Programmer ditugaskan dengan dengan aman menyimpan kata sandi pengguna akhir dalam database untuk aplikasi web; atau menyimpan kata sandi pada disk untuk login ke perangkat lunak. Dia kemungkinan besar akan:

  1. Dapatkan $password Dari pengguna akhir.
  2. Buat $nonce Sebagai nilai acak sekitar 64 atau 128 bit.
  3. Buat $hash = SHA256($nonce$password) dan simpan $nonce Bersama dengan $hash Dalam database.

Pertanyaan satu:

Mengapa hal berikut tidak jauh lebih baik daripada yang di atas?

  1. Buat $long_string Sekali dan hanya sekali. Simpan ini sebagai konstanta dalam kode aplikasi. $long_string Bisa f.x. menjadi 2 kilobyte karakter acak.
  2. Dapatkan $password Dari pengguna akhir.
  3. Buat $mac = HMAC-SHA256($long_string)[$password] (mis. Buat MAC menggunakan kata sandi pengguna akhir sebagai kunci) dan simpan $mac Ini di basis data.

Saya akan membayangkan HMAC memiliki manfaat berikut?

  • Tabrakan lebih jarang?
  • Ini komputasi agak lebih mahal daripada hashing biasa? (Tapi tentu saja tidak di dekat scrypt.)
  • Agar berhasil dengan serangan brute-force dalam waktu yang wajar, dan penyerang perlu mendapatkan akses ke dua hal: 1) database, di mana $mac Disimpan, dan 2) kode aplikasi, di mana aslinya $long_string disimpan. Itu lebih baik daripada fungsi hash, di mana penyerang hanya perlu akses ke database?

Tapi tetap saja, sepertinya tidak ada yang menyarankan menggunakan HMAC, jadi saya pasti salah paham sesuatu?

Pertanyaan dua:

Apa implikasi dari menambahkan nilai garam $nonce?

  1. Buat $long_string Sekali dan hanya sekali. Simpan ini sebagai konstanta dalam kode aplikasi.
  2. Dapatkan $password Dari pengguna akhir.
  3. Buat $nonce Sebagai nilai acak sekitar 128 bit.
  4. Buat $mac = HMAC-SHA256($long_string)[$nonce$password] dan simpan $nonce Dan $mac Dalam database.
46
Jesper M

Intinya adalah untuk mencegah pembagian biaya serangan: jika seorang penyerang ingin menyerang dua kata sandi, maka itu harus dua kali lebih mahal daripada menyerang satu kata sandi.

Dengan proposal Anda ("pertanyaan 1"), dua pengguna dengan kata sandi yang sama akan menggunakan MAC yang sama. Jika penyerang memiliki akses baca ke basis data Anda, ia dapat "mencoba" kata sandi (dengan menghitung ulang MAC) dan mencari basis data untuk kecocokan. Dia kemudian dapat menyerang semua kata sandi secara paralel, untuk biaya serangan satu. Jika long_string Anda adalah sebuah konstanta hardcoded dalam kode sumber aplikasi, maka semua instal aplikasi yang terinstal membagikan konstanta ini, dan menjadi bermanfaat (bagi penyerang) untuk membuat kamus besar pasangan kata sandi ke MAC , Juga dikenal sebagai "a Rainbow table".

Dengan nonce ("pertanyaan 2") Anda, Anda menghindari pembagian biaya. Nonce biasanya dikenal sebagai "garam". long_string Anda dan penggunaan HMAC tidak membeli Anda banyak di sini (dan Anda tidak menggunakan HMAC untuk apa itu dirancang, omong-omong, sehingga Anda berada pada fondasi yang goyah, berbicara secara kriptografis). Menggunakan garam adalah ide yang sangat bagus (well, tidak menggunakan garam adalah ide yang sangat buruk, setidaknya) tetapi hanya melakukan setengah dari pekerjaan. Anda juga harus memiliki prosedur hashing lambat. Intinya di sini adalah bahwa garam mencegah pembagian biaya, tetapi tidak mencegah menyerang satu kata sandi. Menyerang kata sandi berarti mencoba kemungkinan kata sandi sampai satu yang cocok (itulah "serangan kamus"), dan, mengingat imajinasi rata-rata pengguna manusia, serangan kamus cenderung bekerja: orang hanya cinta menggunakan kata sandi yang dapat tebak. Solusinya adalah dengan menggunakan proses hashing yang secara inheren lambat, biasanya dengan mengulangi fungsi hash beberapa ribu kali. Idenya adalah untuk membuat verifikasi kata sandi lebih mahal: membuat pengguna menunggu 1ms bukannya 1μs bukanlah kesulitan (pengguna tidak akan menyadarinya), tetapi juga akan membuat serangan kamus 1000 kali lebih mahal. long_string Anda boleh digunakan untuk itu, asalkan itu sangat panjang (bukan 2 kilobyte, lebih dari 20 megabita).

HMAC boleh digunakan sebagai ganti fungsi hash mentah untuk memperkuat sistem verifikasi kata sandi, tetapi dalam pengaturan yang berbeda. Dengan sistem yang memeriksa kata sandi dengan garam dan fungsi hash yang diulang, Anda dapat mengganti fungsi hash dengan HMAC, menggunakan kunci rahasia K . Ini mencegah serangan kamus offline selama Anda dapat menyimpan K rahasia. Menjaga kerahasiaan nilai tidak mudah, tetapi masih lebih mudah untuk menjaga 128-bit K rahasia daripada database lengkap.

35
Thomas Pornin

HMAC tidak membeli Anda banyak di sini meskipun saya kira itu bertindak sebagai fungsi hash yang dapat diganti (diganti dengan mengubah kunci). Pokoknya sepertinya berlebihan di sini.

Namun, skema pertama yang Anda usulkan di atas gagal secara serempak jika $ long_string diketahui oleh penyerang, yang mungkin karena kode mungkin tidak dianggap sebagai rahasia (dan itu adalah praktik yang buruk jika mengandalkan kerahasiaan kode bagaimanapun).

Anda harus menggunakan skema kedua karena $ nonce diperlukan untuk melindungi terhadap serangan yang sudah dikomputasi.

3
frankodwyer