Hash password với salt - Đã nấu ăn là phải có muối

Những gì chúng ta được học ở trường

Tất tần tật những dev có tâm chúng ta đều biết rằng

  • Phải băm (hash) password trước khi lưu vào trong database
  • Password được mã hóa một chiều, tức là từ chuỗi hash không thể suy ngược ra password

Tuy nhiên password thực sự được hash như thế nào, hôm nay chúng ta sẽ cùng đi tìm hiểu 😄

Ok, hãy bắt đầu từ những thứ nhỏ nhất

2 password giống nhau cho ra cùng 1 chuỗi hash

Ở đây dễ dàng có thể nhận ra được alicebob cùng dung chung mật khẩu có chuỗi hash

4420d1918bbcf7686defdf9560bb5087d20076de5f77b7cb4c3b40bf46ec428b

Ta đặt đây là vấn đề thứ nhất

Tìm password đã được hash

Ok, giờ tưởng tượng rằng chúng ta là một hacker lành nghề đã truy cập vào được database, cùng xem thử có cách nào giải được password hay không

Nào, ta cùng xây dựng ra một hash_table từ các password trong dictionary (từ điển tiếng anh chẳng hạn), sau đó compare với từng chuỗi hash trong database chôm được. 2 chuỗi khác nhau có thể cho ra cùng 1 chuỗi hash, tuy nhiên xác suất là rất nhỏ. Tuy vậy làm thế nào biết được thuật toán hash nào được sử dụng, điều này không quá khó

May mắn thay, alicebob đều sử dụng password hiếm xuất hiện trong các bộ dictionary là dontpwnme4. Tuy nhiên, người gặp nguy hiểm nhất là anh chàng mike khi chọn password của mình là friendship .Điều nay kéo theo nguy hiểm cho alice & bob khi chúng ta có thể dò ra dontpwnme4 thông qua một bộ dictionary đặc biệt leetspeak để crack password.

Tuy vậy phương pháp dictionary attack và brute-force này tính toán các hash trong hash_table theo thời gian thực, điều này đỏi hỏi khá nhiều thời gian, nên hacker chúng ta nên sử dụng rainbow table. Được lợi về thời gian thì phải chi trả bằng bộ nhớ. Rainbow table attack nhanh hơn đơn giản chỉ vì các hash đã được tính toán sẵn. Và điều kinh dị nhất mùa hè này là rainbow_table so sánh một lúc tất cả các hash trong database mà không có chút trở ngại nào.

Ta đặt đây là vấn đề 2

Thêm chút muối làm khó chàng hacker tài năng

Vậy thì, làm thế nào chúng ta có thể gây khó dễ cho anh chàng ở trên, thêm cho anh ta chút muối thôi.

Salt là một chuỗi random với độ dài nhất định được thêm vào input trước khi đưa vào hash.

Như vậy chúng ta giải quyết được vấn đề thứ nhất alice & bob đặt chung 1 password bằng cách chèn thêm cho mỗi người 1 salt, đường ai nấy đi. Nào cùng rắc chút muối lên alice E1F53135E559C253, thêm chút nữa vào bob 84B03D034B409D4E . Lúc này hashed_password của anh chị này sẽ là.

bob_co_muoi = SHA256(dontpwnme4E1F53135E559C253) = BE5D7F437224662EBA29A79A1648477EE0350E6CA29633ABE704E2066562F14D

alice_co_muoi = SHA256(dontpwnme484B03D034B409D4E) = D9C7DDB003854E1E12436AF13D6F9D6690399418BF59650FEDC0F9D5A4478CDD

Ok, vậy chúng ta sẽ lưu trữ salt và hashed_password trong database. Khi một user truy cập, ta đem chuỗi password cộng với muối xào ra gì đó rồi so sánh với hashed_password. Với anh chàng hacker kia thì phải xây dựng một rainbow table với từng salt khi muốn crack 1 password 😂. Rainbow table giờ không thể dùng để so sánh nhiều hashed_password được nữa, thế là giải quyết xong vấn đề thứ 2 😜

Note: Hãy chắc chắn rằng bạn generate được một salt đủ mạnh sử dụng CSPRNG, đừng tự random chuỗi như mình nhé 😂. Thực tế chúng ta cũng sẽ không sử dụng SHA256 mà sử dụng các hàm hash chậm như bcrypt, scrypt,.. Còn lý do thì tại càng chậm thì càng bất lợi cho chàng hacker chứ sao.

References:

https://en.wikipedia.org/wiki/Salt_(cryptography)

https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/