SecOps Portal
Trang chủ › Nghiên Cứu Bảo Mật

Tìm hiểu cơ chế mã hóa mật khẩu bằng hàm băm Bcrypt

Ban biên tập SecOps Portal · · Cập nhật
Tìm hiểu cơ chế mã hóa mật khẩu bằng hàm băm Bcrypt

Bcrypt là hàm băm mật khẩu được thiết kế để chậm có chủ đích, kết hợp muối (salt) ngẫu nhiên và hệ số chi phí (cost factor) có thể điều chỉnh. Nhờ đó, ngay cả khi cơ sở dữ liệu bị lộ, kẻ tấn công phải tốn rất nhiều thời gian để đoán từng mật khẩu, và hai người dùng cùng mật khẩu vẫn có chuỗi băm khác nhau. Gọi là "mã hóa mật khẩu" cho quen, nhưng chính xác thì bcrypt là băm: một chiều, không giải mã ngược được.

Vì sao không lưu mật khẩu dạng thường hay băm nhanh

Lưu mật khẩu dạng văn bản thường thì một lần lộ cơ sở dữ liệu là lộ toàn bộ. Mã hóa hai chiều cũng không ổn vì khóa giải mã thường nằm cùng hệ thống. Giải pháp đúng là băm: lưu kết quả của hàm một chiều, khi đăng nhập thì băm mật khẩu nhập vào rồi so sánh.

Nhưng không phải hàm băm nào cũng phù hợp. MD5, SHA-1, SHA-256 được thiết kế để nhanh, phục vụ kiểm tra toàn vẹn dữ liệu. Với phần cứng đồ họa hiện đại, kẻ tấn công có thể thử một lượng khổng lồ mật khẩu mỗi giây với các hàm này. Mật khẩu ngắn hoặc phổ biến sẽ bị tìm ra rất nhanh.

Cách lưuVấn đề
Văn bản thườngLộ ngay toàn bộ
Mã hóa hai chiềuLộ khóa là lộ tất cả
MD5/SHA không muốiTra bảng băm có sẵn, mật khẩu giống nhau có băm giống nhau
SHA có muốiTốt hơn nhưng vẫn quá nhanh, dễ dò bằng GPU
bcrypt, scrypt, Argon2, PBKDF2Chậm có chủ đích, có muối, phù hợp cho mật khẩu

Bcrypt hoạt động như thế nào

Bcrypt được công bố năm 1999, dựa trên thuật toán mã hóa Blowfish. Điểm then chốt là giai đoạn thiết lập khóa tốn kém (gọi là EksBlowfish), được lặp lại 2 mũ cost lần. Quá trình tổng quát:

  1. Sinh muối ngẫu nhiên 16 byte cho mỗi mật khẩu.
  2. Dùng mật khẩu và muối để thiết lập trạng thái nội bộ của Blowfish, lặp lại số vòng theo hệ số chi phí.
  3. Dùng trạng thái đó mã hóa một chuỗi cố định nhiều lần để ra kết quả băm.
  4. Ghép phiên bản thuật toán, hệ số chi phí, muối và kết quả thành một chuỗi duy nhất để lưu.

Đọc chuỗi băm bcrypt

Một chuỗi bcrypt có dạng bắt đầu bằng $2b$, tiếp theo là hệ số chi phí hai chữ số (ví dụ 12), rồi 22 ký tự muối và 31 ký tự kết quả băm, mã hóa theo biến thể base64 riêng. Vì muối và chi phí nằm ngay trong chuỗi, bạn chỉ cần lưu một trường trong cơ sở dữ liệu; thư viện tự đọc các thông số khi xác minh.

  • $2b$: phiên bản thuật toán. Các tiền tố $2a$, $2y$ là biến thể cũ hoặc theo cách triển khai.
  • Hệ số chi phí: mỗi lần tăng 1, thời gian tính gấp đôi.
  • Muối: bảo đảm hai mật khẩu giống nhau cho kết quả khác nhau, vô hiệu hóa bảng băm tính sẵn.

Chọn hệ số chi phí

Hệ số chi phí là sự cân bằng giữa an toàn và hiệu năng. Mục tiêu thường được khuyến nghị là để mỗi lần băm mất một khoảng thời gian chấp nhận được trên máy chủ của bạn, đủ chậm với kẻ tấn công nhưng không làm đăng nhập ì ạch. Hướng dẫn của OWASP đặt mức tối thiểu là 10. Cách làm thực tế: đo thời gian băm trên phần cứng sản xuất, chọn giá trị phù hợp, và định kỳ tăng lên khi phần cứng mạnh hơn.

Khi tăng hệ số chi phí, bạn không cần ép người dùng đổi mật khẩu: ở lần đăng nhập thành công tiếp theo, kiểm tra hệ số trong chuỗi băm cũ, nếu thấp hơn mức hiện tại thì băm lại mật khẩu vừa nhập với hệ số mới và cập nhật.

Những giới hạn cần biết

  • Giới hạn 72 byte: bcrypt chỉ dùng tối đa 72 byte đầu của mật khẩu. Với tiếng Việt có dấu mã hóa UTF-8, mỗi ký tự có thể chiếm nhiều byte. Nếu cho phép mật khẩu rất dài, cân nhắc giới hạn độ dài hợp lý hoặc dùng thuật toán khác. Cách băm trước bằng SHA rồi đưa vào bcrypt cần làm cẩn thận (mã hóa base64 kết quả) để tránh lỗi byte rỗng.
  • Không dùng nhiều bộ nhớ: bcrypt chậm về tính toán nhưng ít tốn bộ nhớ, nên phần cứng chuyên dụng vẫn có lợi thế nhất định.
  • Tấn công từ chối dịch vụ: vì băm chậm, endpoint đăng nhập cần giới hạn tần suất để không bị lợi dụng làm quá tải máy chủ.

Bcrypt so với Argon2, scrypt, PBKDF2

Thuật toánĐặc điểm
Argon2idThắng cuộc thi Password Hashing Competition, tốn cả CPU và bộ nhớ; được OWASP ưu tiên cho hệ thống mới
scryptTốn bộ nhớ, chống phần cứng chuyên dụng tốt
bcryptTrưởng thành, hỗ trợ rộng rãi, vẫn là lựa chọn tốt khi Argon2 không sẵn có
PBKDF2Đáp ứng một số yêu cầu tiêu chuẩn chính phủ, cần số vòng lặp rất cao

Với hệ thống đang chạy bcrypt cấu hình đúng, không có lý do cấp bách để chuyển đổi. Với dự án mới, Argon2id là lựa chọn mặc định nên cân nhắc.

Dùng bcrypt đúng trong ứng dụng

  • Dùng thư viện bcrypt chuẩn của ngôn ngữ, không tự triển khai.
  • Dùng hàm xác minh của thư viện thay vì tự so sánh chuỗi, để tránh lỗi và tấn công dựa trên thời gian.
  • Không ghi mật khẩu thô vào log, kể cả log lỗi.
  • Kết hợp kiểm tra mật khẩu mới với danh sách mật khẩu đã lộ.
  • Giới hạn số lần đăng nhập sai và hỗ trợ xác thực đa yếu tố.

Băm mật khẩu đúng cách giảm thiệt hại khi cơ sở dữ liệu bị lộ, ví dụ qua lỗ hổng SQL Injection, nhưng không ngăn được mật khẩu bị đánh cắp ngay ở máy người dùng, như với phần mềm ghi bàn phím. Đây là lý do xác thực đa lớp vẫn cần thiết. Nhóm lỗi lưu trữ mật khẩu yếu thuộc mục lỗi mật mã trong OWASP Top 10.

Câu hỏi thường gặp

Bcrypt có giải mã ngược được không?

Không. Bcrypt là hàm băm một chiều. Cách duy nhất để tìm mật khẩu là đoán và băm thử từng ứng viên, việc mà hệ số chi phí khiến trở nên rất tốn kém.

Có cần tự tạo muối khi dùng bcrypt?

Không. Thư viện bcrypt tự sinh muối ngẫu nhiên và nhúng vào chuỗi kết quả. Bạn chỉ cần lưu chuỗi đó và dùng hàm xác minh của thư viện.

Nên chuyển từ MD5 sang bcrypt thế nào khi đã có người dùng?

Một cách phổ biến là băm lại giá trị MD5 cũ bằng bcrypt cho toàn bộ tài khoản ngay lập tức, rồi khi người dùng đăng nhập thì thay bằng bcrypt của mật khẩu gốc. Như vậy không còn MD5 trần trong cơ sở dữ liệu.

Mật khẩu dài hơn 72 byte có an toàn với bcrypt không?

Phần vượt quá 72 byte bị bỏ qua, nên hai mật khẩu chung 72 byte đầu sẽ được coi là giống nhau. Với đa số người dùng điều này không đáng kể, nhưng hệ thống cho phép mật khẩu rất dài nên giới hạn độ dài hoặc dùng Argon2.

Bài liên quan