Băm, muối, bcrypt và Argon2: một trang web tử tế làm gì với mật khẩu của bạn

Đăng ngày bởi David Carrero

Một trang web tử tế không biết mật khẩu của bạn. Không phải nó không muốn biết: nó không thể.

Nghe như mẹo vặt, vì mỗi lần bạn gõ mật khẩu vào thì hệ thống lại cho bạn vào, mà muốn cho vào thì phải kiểm tra một thứ gì đó. Nhưng kiểm tra không phải là biết. Máy chủ giữ một dấu vân tay được tính ra từ mật khẩu của bạn; khi bạn gõ, nó tính lại dấu vân tay đó rồi đem so. Trùng thì mời vào. Không có lúc nào cần đến việc mật khẩu được chép ra ở đâu đó cả.

Từ đây mà ra dấu hiệu rõ nhất để phân biệt một dịch vụ nghiêm túc với một dịch vụ không nghiêm túc: nếu bạn quên mật khẩu mà họ gửi lại nó cho bạn qua email, thì họ đã lưu nó. Và cái gì đã được lưu thì sớm muộn cũng rơi vào tay người khác.

1979 ý tưởng đừng lưu chúng — và ý tưởng làm chuyện đó thật chậm

Năm 1979, Robert Morris và Ken Thompson công bố trên Communications of the ACM bài “Password Security: A Case History”, kể lại những gì họ đã làm trong Unix. Đó là một bản tường thuật của kinh nghiệm, và trong đó có hai ý tưởng mà hôm nay ta coi là hiển nhiên.

Ý thứ nhất không phải họ nghĩ ra — lưu giá trị băm thay vì lưu mật khẩu đã có người làm trước đó — nhưng họ giải thích nó hay hơn bất kỳ ai: đừng lưu mật khẩu, hãy lưu hàm băm của nó. Một hàm biến mật khẩu của bạn thành một giá trị trông như vô nghĩa và không thể đi ngược lại: từ giá trị băm không quay về được mật khẩu.

Ý thứ hai thì đúng là của họ: muối. Một giá trị ngẫu nhiên khác nhau cho từng người dùng, được trộn vào mật khẩu trước khi băm. Không có muối, hai người đặt cùng một mật khẩu sẽ có cùng một giá trị băm — tệp bị đánh cắp biến thành trò tìm những dòng trùng nhau — và tệ hơn, có kẻ có thể tính trước một bảng khổng lồ đúng một lần rồi đem dùng cho mọi cơ sở dữ liệu trên đời. Muối không làm mật khẩu của bạn khó đoán hơn: nó làm cho việc đoán ra nó chẳng giúp ích gì cho bất kỳ ai khác.

Nhưng trong chính bài viết ấy còn có ý thứ ba, ít được trích dẫn hơn hẳn, và đó mới là ý quan trọng ở đây: họ làm cho hàm chậm một cách có chủ đích. Không phải do cẩu thả. Mà cố tình. Mã hóa một mật khẩu tốn kém hơn nhiều so với mức kỹ thuật đòi hỏi, bởi vì người mỗi sáng đăng nhập một lần thì chẳng thấy khác biệt, còn kẻ thử hàng triệu ứng viên thì có.

Toàn bộ câu chuyện nằm gọn trong một câu từ gần năm mươi năm trước.

Vì sao sự chậm chạp là phòng tuyến trung thực duy nhất

Gần như mọi phòng tuyến trong tin học đều bất đối xứng: rẻ với người phòng thủ và đắt với kẻ tấn công. Mã hóa thì rẻ; giải mã mà không có khóa thì bất khả thi. Người phòng thủ có lợi thế về mặt cấu trúc.

Việc lưu trữ mật khẩu thì không. Ở đây người phòng thủ và kẻ tấn công chạy đúng một hàm giống hệt nhau. Bạn tính giá trị băm để kiểm tra xem mình có gõ đúng không; hắn tính nó để kiểm tra xem hắn có đoán đúng không. Đây là cuộc đua duy nhất trong ngành bảo mật mà cả hai chạy bằng cùng một đôi chân.

Khi không thể chạy nhanh hơn đối thủ, chỉ còn một nước đi: làm cho đường đua đắt hơn cho cả hai. Bạn trả cái giá đó một lần cho mỗi lần đăng nhập. Hắn trả một lần cho mỗi lần thử. Vì hắn cần số lần thử lớn hơn bạn nhiều bậc độ lớn, cùng một hóa đơn ấy tác động lên hai bên theo cách không thể so sánh. Đó chính là việc mà một hàm băm mật khẩu làm.

Vì vậy những hàm nhanh và tuyệt vời cho việc khác — SHA-256 chẳng hạn — lại là lựa chọn tồi tệ ở đây. Chúng nhanh. Mà nhanh đúng là thứ ta không muốn.

1999 bcrypt, và chi phí như một chi tiết vặn được

Rắc rối của một hàm chậm là phần cứng không chịu đứng yên. Thứ chậm chạp năm 1979 về sau trở thành tức thời. Một phòng tuyến hiệu chỉnh theo máy tính của một thập kỷ sẽ tự già đi, chẳng cần ai động vào.

Năm 1999, Niels Provos và David Mazières giới thiệu bcrypt tại USENIX Annual Technical Conference, với một nhan đề đã nói hết: A Future-Adaptable Password Scheme.

Ý tưởng: đặt chi phí không nằm trong hàm, mà nằm trong một tham số. bcrypt mang theo một hệ số chi phí do bạn quyết định và được lưu ngay cạnh giá trị băm. Nếu phần cứng nhanh lên nhiều, bạn tăng con số ấy và những mật khẩu mới lại tốn đúng mức đáng phải tốn, chẳng cần đổi thuật toán.

Đó là một thiết kế thừa nhận sự lỗi thời của chính nó và chuẩn bị sẵn cho điều đó. Rất hiếm phần mềm nào làm được vậy.

2009 scrypt, và phát hiện rằng thời gian là chưa đủ

bcrypt làm cho thời gian tính toán đắt lên, và nó đã hiệu quả. Cho đến khi kẻ tấn công thôi không dùng cùng loại máy với người phòng thủ nữa.

Một máy chủ có vài nhân nhanh, đa dụng. Một GPU có vô số nhân nhỏ làm cùng một việc song song, còn ASIC thì đi xa hơn: silicon được chế tạo để chạy đúng một phép toán. Nếu phòng tuyến của bạn là “phép toán này tốn X”, sẽ có người dựng được phần cứng làm thật nhiều X cùng lúc. Còn người phòng thủ vẫn ngồi với cái máy chủ của mình.

Năm 2009, Colin Percival giới thiệu scrypt bằng một lập luận khác: Stronger Key Derivation via Sequential Memory-Hard Functions. Nếu chi phí chỉ nằm ở phép tính, người ta sẽ song song hóa nó. Nhưng bộ nhớ thì không ai cho không. Hãy ép hàm phải dùng thật nhiều RAM và phải đi qua nó theo cách không né được, thế là bỗng dưng kẻ tấn công không thể nhân bản số nhân lên nữa: mỗi nhân sẽ cần bộ nhớ riêng của nó. Mà nhân của GPU thì thừa sức tính toán và thiếu RAM cho mỗi nhân.

Percival không làm phép toán đắt lên. Ông làm cho phần cứng cần để lặp lại nó hàng loạt trở nên đắt. Đó là đổi cấp độ: đánh vào ngân sách của kẻ tấn công, chứ không đánh vào cái đồng hồ của hắn.

2015 Argon2, và hồi kết của cuộc tranh luận

Việc có sẵn vài lựa chọn hợp lý chẳng giúp ai chọn được cả. Thế nên cộng đồng mật mã học làm cái việc họ vẫn hay làm khi muốn khép lại một chuyện: mở một cuộc thi công khai. Password Hashing Competition nhận các ứng viên, đem ra mổ xẻ công khai trong nhiều năm, và năm 2015 xướng tên người thắng cuộc: Argon2.

Argon2 thừa hưởng cả hai bài học: chi phí về thời gian và chi phí về bộ nhớ, cả hai đều chỉnh được riêng biệt, cộng thêm số luồng. Không có phép màu nào ở đây. Nó là bản tổng hợp gọn ghẽ của 1979, 1999 và 2009, được soát lại bởi những người mà công việc chính là cố phá cho bằng được.

Chuyện này có nghĩa gì với bạn

Gần như chẳng có gì trong đó nằm trong tay bạn, và cũng nên nói thẳng: hàm băm do trang web chọn, không phải do bạn. Bạn có thể có mật khẩu hay nhất thế giới mà vẫn bị người ta lưu nguyên văn trong một file Excel.

Nhưng vế còn lại của phương trình thì đúng là tùy ở bạn. Cả tòa nhà này — muối, chi phí, bộ nhớ — dựng lên là để làm mỗi lần thử của kẻ tấn công đắt hơn. Còn thứ quyết định hắn cần bao nhiêu lần thử chính là mật khẩu của bạn. Nếu nó nằm trong từ điển, chẳng hàm chậm nào cứu nổi: nó sẽ đổ ngay trong nhóm đầu tiên. Nếu nó dài và chẳng giống thứ gì, cái giá mỗi lần thử ấy được nhân với một số lần thử không nhét vừa vào quỹ thời gian có được.

Vì vậy trình tạo của chúng tôi đo bit entropy chứ không đo phần trăm, và vì vậy trình kiểm tra tra mật khẩu của bạn trong các từ điển trước khi đi đếm ký hiệu. Họ đặt giá cho mỗi lần thử; bạn đặt số lần thử. Không nửa nào chạy được nếu thiếu nửa kia.

Và đúng vậy: vẫn là câu hỏi muôn thuở ấy thôi. Chỉ có điều bây giờ, ở phía bên kia, có kẻ đang cố trả lời nó rất nhiều lần mỗi giây, và từ năm 1979 đến nay chúng ta vẫn đang cố làm sao cho mỗi lần như thế đều tốn tiền của hắn.


Nguồn: R. Morris và K. Thompson, “Password Security: A Case History”, Communications of the ACM, 1979 · N. Provos và D. Mazières, “A Future-Adaptable Password Scheme”, USENIX Annual Technical Conference, 1999 (bcrypt) · C. Percival, “Stronger Key Derivation via Sequential Memory-Hard Functions”, 2009 (scrypt) · Password Hashing Competition, người thắng cuộc Argon2, 2015.

← Quay lại blog