Tôi nên sử dụng loại / độ dài cột nào để lưu trữ mật khẩu băm Bcrypt trong Cơ sở dữ liệu?


318

Tôi muốn lưu trữ mật khẩu băm (sử dụng BCrypt) trong cơ sở dữ liệu. Điều gì sẽ là một loại tốt cho điều này, và đó sẽ là độ dài chính xác? Các mật khẩu được băm với BCrypt luôn có cùng độ dài?

BIÊN TẬP

Ví dụ băm:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

Sau khi băm một số mật khẩu, có vẻ như BCrypt luôn tạo ra băm 60 ký tự.

CHỈNH SỬA 2

Xin lỗi vì đã không đề cập đến việc thực hiện. Tôi đang sử dụng jBCrypt .


Cũng xem khung băm mật khẩu PHP của Openwall (PHPass). Nó di động và cứng đối với một số cuộc tấn công phổ biến vào mật khẩu người dùng. Anh chàng đã viết khung (SolarDesigner) là cùng một người đã viết John The Ripper và ngồi trong vai trò giám khảo trong Cuộc thi băm mật khẩu . Vì vậy, anh ta biết một hoặc hai điều về các cuộc tấn công vào mật khẩu.
jww

1
Nếu bất cứ ai rơi vào điều này đang tìm kiếm một giải pháp cho tiền điện tử : câu trả lời của Gumbo cũng áp dụng cho tiền điện tử. Cá nhân tôi đã áp dụng BINary (64) trong MySQL và nó cho phép tôi kiểm tra tính bằng byte theo Python sau này.
Philippe Hebert

Câu trả lời:


369

Định dạng mã hóa mô-đun cho bcrypt bao gồm

  • $2$, $2a$Hoặc $2y$xác định các thuật toán băm và định dạng
  • một giá trị hai chữ số biểu thị tham số chi phí, theo sau là $
  • 53 ký tự dài giá trị cơ bản được mã hóa 64 (họ sử dụng bảng chữ cái ., /, 0- 9, A- Z, a- zđó là khác nhau đối với cơ sở tiêu chuẩn 64 Encoding bảng chữ cái) bao gồm:
    • 22 ký tự muối (thực tế chỉ có 128 bit trong số 132 bit được giải mã)
    • 31 ký tự đầu ra được mã hóa (thực tế chỉ có 184 bit trong số 186 bit được giải mã)

Do đó, tổng chiều dài tương ứng là 59 hoặc 60 byte.

Khi bạn sử dụng định dạng 2a, bạn sẽ cần 60 byte. Và do đó cho MySQL tôi sẽ khuyên bạn nên sử dụng CHAR(60) BINARYhayBINARY(60) (xem Các _binnhị phân Collations để biết thông tin về sự khác biệt).

CHARkhông phải là an toàn nhị phân và sự bình đẳng không chỉ phụ thuộc vào giá trị byte mà phụ thuộc vào đối chiếu thực tế; trong trường hợp xấu nhất Ađược coi là bằng a. Xem The _binand binaryCollations để biết thêm thông tin.


28
Lưu ý - lưu trữ dưới dạng nhị phân (60) có thể gây ra hành vi không mong muốn cho sự bình đẳng chuỗi (trong số những thứ khác). Trong .NET, điều này có thể được khắc phục bằng cách sử dụng String.Equals (fromDataBaseBinary60 chuỗi, điển hìnhString, StringComparison.InvariantCARM)
JHubbard80

8
Nếu bạn xác định cột là CHAR (60) CHARACTER SET latin1 COLLATE latin1_bin, thì bây giờ bạn có được những lợi thế của so sánh chuỗi chính xác mà không cần cột nhị phân.
Ben

2
@AndreFigueiredo SQL_Latin1_General_CP1_CS_ASkhông rõ trong MySQL. Những gì được biết là latin1_general_cs.
Gumbo

1
Tôi rất thích có một định nghĩa ở đây cho những gì 2, 2a2ycó nghĩa là cho thuật toán băm và định dạng. Tôi không thể đưa ra một câu trả lời dễ dàng với một số tìm kiếm.
vui vẻ

2
@Neon Vấn đề là bạn có thể so sánh các giá trị băm khác nhau bằng nhau. Nếu bạn xác định rõ ràng rằng đó là cột nhị phân (hoặc VARCHAR với đối chiếu đúng), bạn sẽ không gặp rủi ro, ở một nơi khác, thay đổi một số cài đặt khiến nó trở thành so sánh không phân biệt chữ hoa chữ thường. Nó cũng làm cho ý định của bạn rõ ràng hơn, nói chung là một điều tốt - bạn đang lưu trữ dữ liệu nhị phân; bạn nên lưu trữ nó dưới dạng dữ liệu nhị phân.
Vụ kiện của Quỹ Monica

52

Băm Bcrypt có thể được lưu trữ trong một BINARY(40)cột.

BINARY(60), như các câu trả lời khác gợi ý, là lựa chọn dễ dàng và tự nhiên nhất, nhưng nếu bạn muốn tối đa hóa hiệu quả lưu trữ, bạn có thể tiết kiệm 20 byte bằng cách giải mã băm một cách dễ dàng. Tôi đã ghi lại tài liệu này kỹ lưỡng hơn trên GitHub: https://github.com/ademarre/binary-mcf

Băm mật mã theo một cấu trúc được gọi là định dạng mã hóa mô đun (MCF). Binary MCF (BMCF) giải mã các biểu diễn băm văn bản này thành một cấu trúc nhị phân nhỏ gọn hơn. Trong trường hợp Bcrypt, băm nhị phân kết quả là 40 byte.

Gumbo đã làm rất tốt khi giải thích bốn thành phần của hàm băm MCF Bcrypt:

$<id>$<cost>$<salt><digest>

Giải mã cho BMCF như sau:

  1. $<id>$ có thể được biểu diễn trong 3 bit.
  2. <cost>$, 04-31, có thể được biểu thị trong 5 bit. Đặt chúng cùng nhau trong 1 byte.
  3. Muối 22 ký tự là đại diện cơ sở 64 (không chuẩn) gồm 128 bit. Giải mã Base-64 mang lại 16 byte.
  4. Bản tóm tắt băm 31 ký tự có thể được giải mã cơ sở 64 thành 23 byte.
  5. Đặt tất cả lại với nhau trong 40 byte: 1 + 16 + 23

Bạn có thể đọc thêm tại liên kết ở trên hoặc kiểm tra việc triển khai PHP của tôi , cũng trên GitHub.


49
Chi phí của trường dài hơn: 20 byte lần thậm chí một triệu + bản ghi: 20MB, khi bạn đạt tới một triệu bản ghi +. Chi phí thực hiện không đúng chiều dài trường rút ngắn, trong lĩnh vực kỹ thuật & bảo mật rất phức tạp: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Bạn làm toán.
Kzqai

6
@Kzqai, như tôi đã nói, cột 60 byte lớn hơn là sự lựa chọn tự nhiên nhất, nhưng việc tích cực theo đuổi hiệu quả lưu trữ phụ thuộc vào dự án như thế nào. Ví dụ: thông thường là cố gắng điều chỉnh toàn bộ cơ sở dữ liệu trong bộ nhớ và 20 MB ở đây và 20 MB khác ở đó có thể tăng lên nhanh chóng trong môi trường bị giới hạn bộ nhớ.
Andre D

10
Ví dụ của bạn ăn vào quan điểm của tôi. --- Nếu bạn muốn đặt cơ sở dữ liệu của mình vào bộ nhớ, hãy tối ưu hóa mọi cột khác trước khi chạm vào cột lưu trữ bcrypt. --- Nếu bạn đã tối ưu hóa mọi cột khác ở mức độ điên rồ và chỉ còn lại cột băm bcrypt, hãy lấy một bộ nhớ khác chỉ dành cho bcrypt. --- Nếu bạn đã thực hiện cả hai điều trên ... ... dừng lại, bạn đã tối ưu hóa mọi cột trái cây treo thấp khác và bạn sẽ gặp rắc rối với hệ thống bảo mật mật mã được thử nghiệm hoạt động và thay thế nó với một hệ thống trồng tại nhà phức tạp hơn với cơ hội thất bại.
Kzqai

11
@Kzqai Không có nguy cơ làm suy yếu tính bảo mật của thư viện Bcrypt của bạn ở đây. Đó là mã hóa dữ liệu được hoàn tác khi truy xuất từ ​​bộ lưu trữ trước khi kiểm tra mật khẩu. Đây không phải là lãnh thổ "không cuộn tiền điện tử của riêng bạn".
Andre D

1
Giải thích tốt đẹp. :) Mặc dù lời giải thích của bạn đã đưa ra một ý tưởng tuyệt vời, tôi chỉ muốn đi với 60 ký tự, thậm chí 100 ký tự, chỉ để ở bên an toàn. Cuộc tranh luận thú vị quá @Kzqai và AndreD
Naveen Kumar V

23

Nếu bạn đang sử dụng PHP password_hash()với PASSWORD_DEFAULTthuật toán để tạo ra bcrypt băm (mà tôi cho rằng sẽ có một tỷ lệ lớn người đọc câu hỏi này), hãy nhớ rằng trong tương laipassword_hash() có thể sử dụng thuật toán khác làm mặc định và do đó có thể ảnh hưởng đến độ dài của hàm băm (nhưng nó có thể không nhất thiết dài hơn).

Từ trang hướng dẫn:

Lưu ý rằng hằng số này được thiết kế để thay đổi theo thời gian khi các thuật toán mới và mạnh hơn được thêm vào PHP. Vì lý do đó, độ dài của kết quả từ việc sử dụng mã định danh này có thể thay đổi theo thời gian. Do đó, nên lưu trữ kết quả trong cột cơ sở dữ liệu có thể mở rộng hơn 60 ký tự (255 ký tự sẽ là một lựa chọn tốt).

Sử dụng bcrypt, ngay cả khi bạn có 1 tỷ người dùng (tức là bạn hiện đang cạnh tranh với facebook) để lưu trữ băm mật khẩu 255 byte, nó sẽ chỉ ~ 255 GB dữ liệu - có kích thước bằng một ổ cứng SSD nhỏ. Điều cực kỳ khó xảy ra là việc lưu trữ mật khẩu băm sẽ là nút cổ chai trong ứng dụng của bạn. Tuy nhiên, trong trường hợp không chắc rằng dung lượng lưu trữ thực sự một vấn đề vì một số lý do, bạn có thể sử dụng PASSWORD_BCRYPTđể buộc password_hash()sử dụng bcrypt, ngay cả khi đó không phải là mặc định. Chỉ cần đảm bảo được thông báo về bất kỳ lỗ hổng nào được tìm thấy trong bcrypt và xem lại các ghi chú phát hành mỗi khi phiên bản PHP mới được phát hành. Nếu thuật toán mặc định được thay đổi, sẽ tốt hơn nếu xem xét lý do và đưa ra quyết định sáng suốt có nên sử dụng thuật toán mới hay không.


20

Tôi không nghĩ rằng có bất kỳ thủ thuật gọn gàng nào bạn có thể thực hiện khi lưu trữ điều này như bạn có thể làm ví dụ với hàm băm MD5.

Tôi nghĩ rằng cách tốt nhất của bạn là lưu trữ nó CHAR(60)vì nó luôn dài 60 ký tự


Mặc dù, tài liệu PHP lưu ý rằng các cột sẽ có thể chứa nhiều dữ liệu hơn, cho các bản phát hành trong tương lai ...
Julian F. Weinert

16
Không có lý do để tấm vàng. Nếu phần mềm bạn đang sử dụng yêu cầu sáu mươi byte, thì hãy phân bổ sáu mươi byte. Nếu có một bản phát hành trong tương lai cho phần mềm của bạn thay đổi điều này, thì bạn có thể lo lắng về phần mềm đó khi bản phát hành đó xảy ra. Bạn không nên tự động cài đặt các bản cập nhật thay đổi chức năng.
Tyler Crompton
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.