Băm mật khẩu thực sự bảo vệ bạn khỏi điều gì
Băm mật khẩu không phải là phép màu. Đó là cơ chế kiểm soát thiệt hại cho ngày bảng người dùng của bạn bị rò rỉ.
Mục lục
- Phiên bản ngắn gọn
- Hàm băm mật khẩu là gì
- Băm bảo vệ bạn khỏi điều gì
- 1. Lộ mật khẩu ngay lập tức sau một vụ xâm phạm cơ sở dữ liệu
- 2. Tấn công hàng loạt vào toàn bộ cơ sở người dùng của bạn
- 3. Đoán ngoại tuyến tốc độ cao
- Băm không bảo vệ bạn khỏi điều gì
- 1. Phishing
- 2. Credential stuffing
- 3. Mật khẩu bị ghi lại trong log hoặc analytics
- 4. Bảo mật phiên kém
- 5. Đặt lại mật khẩu và khôi phục tài khoản yếu
- Lựa chọn thuật toán: hiện nên dùng gì
- Hệ số chi phí không phải đặt một lần rồi quên
- Pepper: hữu ích, nhưng không phải vật thay thế
- Checklist vận hành
- Mô hình tư duy trung thực
Phiên bản ngắn gọn
Băm mật khẩu bảo vệ người dùng khi cơ sở dữ liệu mật khẩu của bạn bị đánh cắp.
Đó là nhiệm vụ chính. Không phải chi tiết duy nhất, không phải toàn bộ mô hình bảo mật, nhưng là lý do cốt lõi khiến chúng ta băm mật khẩu thay vì lưu trực tiếp.
Một mật khẩu được băm đúng cách rất khó đảo ngược. Nếu kẻ tấn công lấy được bản sao bảng người dùng của bạn, chúng không nên lập tức biết rằng mật khẩu của Alice là Spring2026!. Thay vào đó, chúng nhận được một hàm băm đã lưu, thứ đòi hỏi thời gian, tiền bạc và phần cứng để kiểm thử với các phỏng đoán.
Sự khác biệt đó rất quan trọng. Băm mật khẩu không nhằm tự mình làm cho đăng nhập trở nên an toàn. Nó không ngăn phishing. Nó không ngăn ai đó thử các mật khẩu đã rò rỉ trên biểu mẫu đăng nhập của bạn. Nó không bảo vệ cookie phiên sau khi đăng nhập. Nó mua thêm thời gian và giảm thiệt hại sau một lỗi rất cụ thể: nơi lưu trữ bộ xác minh mật khẩu của bạn bị lộ.
Nếu hiểu ranh giới đó, bạn sẽ đưa ra quyết định tốt hơn về thuật toán, hệ số chi phí, đặt lại mật khẩu, ghi log và ứng phó sự cố.
Hàm băm mật khẩu là gì
Hàm băm mật khẩu là đầu ra của một hàm một chiều áp dụng lên mật khẩu, thường kèm một salt duy nhất và một thuật toán băm mật khẩu được cố ý làm chậm.
Khi người dùng tạo tài khoản, hệ thống nên làm đại khái như sau:
- Nhận mật khẩu qua HTTPS.
- Tạo một salt ngẫu nhiên, duy nhất.
- Chạy mật khẩu và salt qua một hàm băm mật khẩu như Argon2id, bcrypt, scrypt hoặc PBKDF2.
- Lưu tên thuật toán, tham số, salt và hàm băm kết quả.
- Loại bỏ mật khẩu gốc.
Khi người dùng đăng nhập sau đó, hệ thống lặp lại cùng quy trình băm với mật khẩu được gửi lên và các tham số đã lưu. Nếu hàm băm kết quả khớp với hàm băm đã lưu, đăng nhập thành công.
Phần quan trọng là: ứng dụng không cần biết mật khẩu gốc. Nó chỉ cần xác minh rằng mật khẩu được gửi lên tạo ra kết quả mong đợi.
Đây là lý do lưu mật khẩu bằng mã hóa có thể đảo ngược thường là mô hình sai. Nếu ứng dụng của bạn có thể giải mã mọi mật khẩu, thì bất kỳ ai đánh cắp khóa giải mã cũng có thể làm điều tương tự. Thông thường, mật khẩu nên không thể xác minh ngược, chứ không chỉ đơn thuần được che giấu.
Băm bảo vệ bạn khỏi điều gì
1. Lộ mật khẩu ngay lập tức sau một vụ xâm phạm cơ sở dữ liệu
Nếu kẻ tấn công đánh cắp cơ sở dữ liệu chứa mật khẩu dạng văn bản thuần, thiệt hại xảy ra ngay tức thì. Mọi mật khẩu đều bị lộ. Người dùng gặp rủi ro không chỉ trên trang của bạn, mà ở bất cứ đâu họ đã dùng lại mật khẩu đó.
Nếu cơ sở dữ liệu chứa mật khẩu được băm tốt, kẻ tấn công phải làm nhiều việc hơn. Chúng phải đoán các mật khẩu ứng viên, băm từng phỏng đoán với đúng salt và tham số, rồi so sánh kết quả.
Với mật khẩu yếu, việc này vẫn có thể nhanh. Với mật khẩu mạnh và duy nhất, việc đó có thể không thực tế.
Băm biến một vụ lộ lọt thảm họa thành một cuộc chạy đua: người dùng có thể đặt lại mật khẩu và bạn có thể khoanh vùng sự cố trước khi kẻ tấn công bẻ khóa được nhiều mật khẩu hay không?
Điều đó không hoàn hảo. Nó vẫn là một vụ xâm phạm. Nhưng đó là một chế độ thất bại tốt hơn rất nhiều.
2. Tấn công hàng loạt vào toàn bộ cơ sở người dùng của bạn
Salt là một phần then chốt của lưu trữ mật khẩu vì chúng ngăn kẻ tấn công tấn công hiệu quả nhiều người dùng cùng lúc bằng các bảng tính sẵn.
Salt không phải là bí mật. Nó được lưu cùng với hàm băm. Nhiệm vụ của nó là tạo tính duy nhất.
Nếu hai người dùng chọn cùng một mật khẩu, salt duy nhất đảm bảo các hàm băm được lưu của họ khác nhau. Điều đó ngăn kẻ tấn công nhìn lướt qua và thấy nhiều người dùng dùng chung một mật khẩu. Nó cũng ngăn các cuộc tấn công rainbow table cổ điển, nơi kẻ tấn công dùng những danh sách khổng lồ đã tính sẵn ánh xạ từ mật khẩu sang hàm băm.
Không có salt, một hàm băm bị bẻ khóa có thể tiết lộ mọi người dùng có cùng mật khẩu. Có salt, mỗi phỏng đoán mật khẩu phải được kiểm thử riêng cho từng người dùng.
3. Đoán ngoại tuyến tốc độ cao
Một khi kẻ tấn công có cơ sở dữ liệu mật khẩu, chúng có thể đoán ngoại tuyến. Điều đó có nghĩa là giới hạn tần suất đăng nhập, CAPTCHA, chặn IP và giám sát của bạn không còn ý nghĩa. Kẻ tấn công có thể kiểm thử phỏng đoán trên phần cứng của riêng chúng.
Đây là nơi lựa chọn thuật toán trở nên quan trọng.
Các hàm băm đa dụng như SHA-256 và SHA-512 được thiết kế để nhanh. Điều đó tốt cho kiểm tra toàn vẹn tệp và chữ ký số. Nó lại tệ cho lưu trữ mật khẩu.
Các thuật toán băm mật khẩu được thiết kế để chậm, có thể điều chỉnh và đôi khi yêu cầu nhiều bộ nhớ. Argon2id, bcrypt, scrypt và PBKDF2 đều cho phép bạn điều chỉnh tham số chi phí để mỗi phỏng đoán tốn một khoảng thời gian đáng kể.
Argon2id được khuyến nghị rộng rãi cho hệ thống mới vì có thể cấu hình để yêu cầu cả thời gian CPU và bộ nhớ, khiến việc bẻ khóa quy mô lớn bằng GPU trở nên đắt đỏ hơn. bcrypt vẫn phổ biến và chấp nhận được khi cấu hình tốt, dù có các hạn chế như cách xử lý độ dài mật khẩu. PBKDF2 vẫn được dùng trong một số môi trường chịu ràng buộc tuân thủ, đặc biệt khi cần các thành phần được FIPS xác thực.
Nguyên tắc rất đơn giản: làm cho đăng nhập hợp lệ đủ nhanh để chấp nhận được, đồng thời làm cho hàng tỷ phỏng đoán trở nên đắt đỏ.
Băm không bảo vệ bạn khỏi điều gì
1. Phishing
Nếu người dùng nhập mật khẩu vào một trang đăng nhập giả, việc băm trên máy chủ của bạn không giúp được gì. Kẻ tấn công nhận mật khẩu trước khi hệ thống của bạn từng nhìn thấy nó.
Các biện pháp phòng vệ ở đây khác: xác thực đa yếu tố, passkeys, giáo dục người dùng, vệ sinh tên miền, xác thực chống phishing và luồng đặt lại mật khẩu cẩn trọng.
Băm mật khẩu là tuyến phòng thủ dự phòng cho bí mật đã lưu. Nó không phải là biện pháp phòng vệ trước việc người dùng bị lừa giao nộp các bí mật đó.
2. Credential stuffing
Credential stuffing xảy ra khi kẻ tấn công lấy các cặp tên người dùng và mật khẩu bị rò rỉ từ một dịch vụ rồi thử chúng trên dịch vụ khác.
Hàm băm mật khẩu của bạn có thể rất tốt, và credential stuffing vẫn có thể thành công nếu người dùng dùng lại mật khẩu.
Đây là một cuộc tấn công trực tuyến vào biểu mẫu đăng nhập của bạn, không phải một cuộc tấn công ngoại tuyến vào cơ sở dữ liệu. Bạn cần giới hạn tần suất, phát hiện bất thường, kiểm tra mật khẩu đã bị rò rỉ, MFA và chính sách khóa tài khoản hợp lý không tạo cơ hội dễ dàng cho tấn công từ chối dịch vụ.
Cùng tư duy thực tế đó áp dụng cho mọi biểu mẫu bị phơi bày. Nếu bạn đang rà soát bề mặt xác thực của mình, đáng để đọc về lý do biểu mẫu liên hệ là trách nhiệm spam lớn nhất của bạn; cơ chế khác nhau, nhưng bài học tương tự: đầu vào công khai cần kiểm soát lạm dụng, không chỉ cần mã backend sạch.
3. Mật khẩu bị ghi lại trong log hoặc analytics
Băm chỉ hữu ích nếu mật khẩu dạng văn bản thuần được loại bỏ nhanh chóng và không bao giờ bị sao chép sang nơi khác.
Các lỗi phổ biến gồm:
- Ghi log toàn bộ thân yêu cầu trong các lần đăng nhập thất bại.
- Gửi mật khẩu đến công cụ giám sát lỗi.
- Thu thập trường mật khẩu trong sản phẩm phát lại phiên.
- Đưa thông tin xác thực vào URL trong các luồng đặt lại hoặc di chuyển được thiết kế kém.
- Lưu mật khẩu tạm thời dạng văn bản thuần trong quá trình nhập dữ liệu.
Những sai lầm này bỏ qua hoàn toàn việc băm mật khẩu. Nếu văn bản thuần rơi vào log, bản sao lưu, kho dữ liệu hoặc công cụ bên thứ ba, hàm băm của bạn không còn liên quan.
Hãy xem trường mật khẩu như dữ liệu độc hại. Che chúng trước khi ghi log. Loại trừ chúng khỏi analytics. Giữ chúng ngoài URL. Hạn chế người có thể truy cập trace production.
4. Bảo mật phiên kém
Sau khi đăng nhập, trình duyệt của người dùng thường nhận một cookie phiên hoặc token. Nếu token đó bị đánh cắp, kẻ tấn công có thể không cần mật khẩu nữa.
Băm mật khẩu không bảo vệ trước cross-site scripting, cookie không an toàn, session fixation, tạo token yếu hoặc thời hạn phiên quá dài.
Cookie phiên xứng đáng được rà soát riêng: HttpOnly, Secure, SameSite phù hợp, phiên rủi ro cao có thời hạn ngắn và vô hiệu hóa phía máy chủ khi đổi mật khẩu. Bối cảnh quyền riêng tư và trình duyệt rộng hơn cũng liên tục thay đổi, như đã đề cập trong những gì đã thay đổi với cookies năm 2026.
5. Đặt lại mật khẩu và khôi phục tài khoản yếu
Nhiều vụ chiếm đoạt tài khoản không bắt đầu từ mật khẩu. Chúng bắt đầu từ luồng đặt lại.
Nếu token đặt lại có thể dự đoán, tồn tại quá lâu, bị rò rỉ qua referrer header hoặc được gửi đến tài khoản email đã bị xâm phạm, băm mật khẩu sẽ không cứu được bạn.
Hãy dùng token đặt lại có entropy cao, thời hạn ngắn, dùng một lần và thông báo rõ ràng cho người dùng. Vì email thường là kênh khôi phục, xác thực tên miền cơ bản cũng quan trọng. Nếu đội của bạn xem bản ghi DNS như một nghi thức bí ẩn, hãy bắt đầu với một chuyến tham quan thân thiện với lập trình viên về MX, SPF, DKIM và DMARC.
Lựa chọn thuật toán: hiện nên dùng gì
Với ứng dụng mới, hãy dùng Argon2id nếu nền tảng của bạn hỗ trợ tốt. Đây là thuật toán thắng cuộc Password Hashing Competition và được thiết kế cho lưu trữ mật khẩu, bao gồm khả năng chống lại việc bẻ khóa nặng về GPU.
Một thứ bậc hiện đại hợp lý trông như sau:
- Argon2id cho hệ thống mới khi có sẵn.
- bcrypt khi Argon2id không thực tế và hỗ trợ bcrypt đã trưởng thành.
- scrypt khi cấu hình yêu cầu nhiều bộ nhớ được hỗ trợ tốt.
- PBKDF2 khi bị ràng buộc bởi nền tảng hoặc yêu cầu tuân thủ.
Tránh SHA-256, SHA-512, MD5 thuần hoặc một kết hợp tự chế như sha256(password + salt). Hàm băm nhanh không phải là hàm lưu trữ mật khẩu. Những cấu trúc tùy biến có vẻ thông minh thường tệ hơn các chuẩn nhàm chán.
Cũng tránh tự phát minh chính sách mật khẩu dựa trên các chi tiết thuật toán vụn vặt. Người dùng không được lợi từ một danh sách 12 quy tắc về thành phần mật khẩu nếu nó đẩy họ vào các mẫu dễ đoán. Mật khẩu dài và duy nhất, trình quản lý mật khẩu, sàng lọc mật khẩu đã rò rỉ và MFA thường quan trọng hơn.
Hệ số chi phí không phải đặt một lần rồi quên
Băm mật khẩu có các tham số. Argon2id có bộ nhớ, số vòng lặp và mức song song. bcrypt có hệ số chi phí. PBKDF2 có số vòng lặp.
Các giá trị này nên được chọn dựa trên môi trường production của bạn. Quá thấp thì kẻ tấn công đoán rẻ. Quá cao thì hệ thống đăng nhập của bạn trở nên chậm hoặc dễ bị từ chối dịch vụ.
Một mục tiêu thực tế thường nằm trong khoảng vài chục đến vài trăm mili giây cho mỗi lần xác minh mật khẩu trên máy chủ thực tế của bạn, tùy lưu lượng và rủi ro. Hệ thống bảo mật cao có thể chọn cao hơn. Hệ thống quy mô người tiêu dùng có thể cần lập kế hoạch năng lực cẩn thận.
Đừng sao chép một hệ số chi phí từ bài blog năm năm trước. Phần cứng thay đổi. Thư viện thay đổi. Lưu lượng của bạn thay đổi.
Hãy rà soát tham số định kỳ và lên kế hoạch băm lại. Một mẫu phổ biến là lưu thuật toán và tham số cùng mỗi hàm băm. Khi đăng nhập thành công, nếu tham số đã lưu đã lỗi thời, hãy băm lại mật khẩu được gửi lên bằng cấu hình mới hơn và cập nhật bản ghi.
Pepper: hữu ích, nhưng không phải vật thay thế
Pepper là một giá trị bí mật được thêm vào quy trình băm mật khẩu và được lưu tách khỏi cơ sở dữ liệu, thường trong trình quản lý bí mật hoặc mô-đun bảo mật phần cứng.
Khác với salt, pepper phải được giữ bí mật.
Pepper có thể giảm thiệt hại nếu cơ sở dữ liệu bị rò rỉ nhưng bí mật ứng dụng thì không. Chúng hữu ích nhất trong các môi trường trưởng thành có quản lý khóa tốt. Chúng ít hữu ích hơn nếu cùng một kẻ tấn công có thể đánh cắp cả cơ sở dữ liệu và cấu hình ứng dụng.
Nếu dùng pepper, hãy lập kế hoạch xoay vòng cẩn thận. Việc xoay vòng có thể yêu cầu người dùng đăng nhập lại hoặc đặt lại mật khẩu, tùy thiết kế. Pepper là một lớp bổ sung, không phải lý do để làm yếu các thiết lập băm nền tảng.
Checklist vận hành
Nếu bạn chịu trách nhiệm cho một hệ thống thực, checklist thực tế khá ngắn:
- Chỉ lưu mật khẩu bằng một thuật toán băm mật khẩu chuẩn.
- Dùng salt ngẫu nhiên, duy nhất cho mỗi mật khẩu.
- Ưu tiên Argon2id cho bản dựng mới.
- Điều chỉnh tham số chi phí trên phần cứng giống production.
- Lưu thuật toán và tham số cùng mỗi hàm băm.
- Băm lại khi đăng nhập nếu tham số trở nên lỗi thời.
- Không bao giờ ghi log mật khẩu hoặc gửi chúng đến công cụ analytics.
- Dùng TLS ở mọi nơi thông tin xác thực được gửi lên.
- Thêm MFA hoặc passkeys khi rủi ro biện minh cho điều đó.
- Bảo vệ luồng đặt lại nghiêm túc như luồng đăng nhập.
- Có kế hoạch sự cố cho việc buộc đặt lại mật khẩu và thông báo cho người dùng.
Băm mật khẩu không hào nhoáng. Nó là hệ thống ống nước. Nhưng đó là kiểu hệ thống ống nước quyết định liệu một vụ xâm phạm trở thành sự cố đau đớn hay thảm họa trên toàn bộ người dùng.
<!-- tool-cta:start -->
💡 Hãy thử điều này: Xem cùng một đầu vào được ánh xạ tới các thuật toán khác nhau như thế nào với Hash Generator, công cụ làm rõ sự khác biệt giữa các hash nhanh và hash đạt cấp độ mật khẩu.
<!-- tool-cta:end -->
Mô hình tư duy trung thực
Cách tốt nhất để nghĩ về băm mật khẩu là như sau:
Băm không bảo vệ mật khẩu khi người dùng đang gõ nó. Nó không bảo vệ tài khoản sau khi người dùng đã đăng nhập. Nó không bảo vệ người dùng dùng lại mật khẩu trên khắp web.
Nó bảo vệ bộ xác minh đã lưu.
Điều đó nghe có vẻ hẹp, nhưng cực kỳ quan trọng. Cơ sở dữ liệu bị rò rỉ. Bản sao lưu bị rò rỉ. Hệ thống staging bị sao chép. Nhà cung cấp có quyền truy cập mà họ không nên có. Các bản export cũ nằm trong object storage lâu hơn bất kỳ ai còn nhớ.
Khi điều đó xảy ra, thiết kế lưu trữ mật khẩu của bạn trở thành khác biệt giữa việc kẻ tấn công nhận được mật khẩu và việc kẻ tấn công nhận được một bài toán đoán tốn kém.
Đó là điều mà việc băm mật khẩu thực sự bảo vệ bạn khỏi.