Phương pháp lưu trữ mật khẩu trong cơ sở dữ liệu ưa thích


76

Phương thức / kiểu dữ liệu ưa thích của bạn để lưu trữ mật khẩu trong cơ sở dữ liệu là gì (tốt nhất là SQL Server 2005). Cách tôi đã làm trong một số ứng dụng của chúng tôi là trước tiên sử dụng các thư viện mã hóa .NET và sau đó lưu trữ chúng trong cơ sở dữ liệu dưới dạng nhị phân (16). Đây có phải là phương pháp ưa thích hay tôi nên sử dụng một kiểu dữ liệu khác hoặc phân bổ nhiều không gian hơn 16?


1
Tôi có cảm giác đây có thể là một bản dupe nhưng những gì tôi nghĩ có thể là một bản dupe của nó hóa ra lại liên quan đến các thông tin đăng nhập DB thực tế chứ không chỉ lưu trữ các thông tin đăng nhập ứng dụng / trang web.
TheTXI

1
Bạn có thể vui lòng làm rõ câu hỏi của mình để giải thích xem bạn đang sử dụng chức năng "mã hóa" hay "băm"? Tôi nghĩ bạn có nghĩa là sau này, nhưng sự khác biệt là rất đáng kể.
ine

Câu trả lời:


82

Tôi lưu trữ hàm băm có muối tương đương với mật khẩu trong cơ sở dữ liệu và không bao giờ lưu trữ chính mật khẩu, sau đó luôn so sánh mã băm với mật khẩu được tạo trong số những gì người dùng đã chuyển vào.

Quá nguy hiểm khi lưu trữ dữ liệu mật khẩu theo nghĩa đen ở bất kỳ đâu. Điều này khiến cho việc khôi phục không thể thực hiện được, nhưng khi ai đó quên hoặc mất mật khẩu, bạn có thể thực hiện một số bước kiểm tra và tạo mật khẩu mới.


@Quinton: Đó là những gì tôi làm. Với các thư viện mã hóa .net, nó sẽ băm mật khẩu và sau đó tôi chuyển mật khẩu đó vào DB và lưu trữ dưới dạng tệp nhị phân. Tôi chỉ có thể so sánh mật khẩu bằng cách băm đầu vào của người dùng và so sánh nó với những gì được lưu trữ.
TheTXI

1
Tôi khuyên bạn nên sử dụng jbcrypt nếu bạn đang làm việc với java. Cực kỳ đơn giản để sử dụng
Jens Schauder

13
Chúng tôi cũng lưu trữ mật khẩu muối. Trong trường hợp của chúng tôi, chúng tôi chuyển đổi 160-bit phải base64 và lưu trữ nó trong một varchar - nó chỉ làm cho mọi thứ dễ dàng hơn (các chuỗi dễ đọc / ghi / nhìn hơn). Ngoài muối toàn cầu, chúng tôi tạo muối trước với id của người dùng (sid hoặc hướng dẫn) để hai người dùng có cùng mật khẩu không cung cấp cùng một hàm băm. Điều này làm cho các cuộc tấn công từ điển trở nên khó khăn hơn (tốn nhiều CPU hơn) và ngăn bạn phát hiện ra mật khẩu cho nhiều người cùng một lúc, khi mọi người chọn cùng một mật khẩu.
Ian Boyd

@IanBoyd, trong trường hợp bạn chưa thay đổi phương pháp muối, bạn đang làm sai. Nó phải là ngẫu nhiên, với đủ entropy và người dùng cụ thể, trong trường hợp đó, bạn chỉ tuân thủ cái sau.
Francisco Presencia

@FranciscoPresencia Kể từ đó tôi đã chuyển sang bcrypt. Việc triển khai bcrypt chuẩn tạo ra muối ngẫu nhiên cho mỗi hàm băm. Việc triển khai chuẩn cũng chuyển đổi băm 22 byte thành base64, thích hợp để dễ dàng lưu trữ trong một varcharcột cơ sở dữ liệu. Phần suy nghĩ tốt cuối cùng của họ là xác định một định dạng của chuỗi băm của họ, trong đó muối được bao gồm trong chuỗi.
Ian Boyd

49

Phương pháp ưa thích: không bao giờ lưu trữ mật khẩu trong DB của bạn. Chỉ băm của chúng. Thêm muối cho vừa ăn.


6
mod lên, phải làm điều đó, chỉ dành riêng cho những trò đùa muối;)
Jakub

15

Tôi làm điều tương tự như bạn đã mô tả, ngoại trừ nó được lưu trữ dưới dạng Chuỗi. Tôi Base64 mã hóa giá trị nhị phân được mã hóa. Lượng không gian để phân bổ phụ thuộc vào thuật toán mã hóa / độ mạnh của mật mã.

Tôi nghĩ bạn đang làm đúng (cho rằng bạn sử dụng Salt ).


9
  1. lưu trữ băm của mật khẩu muối, chẳng hạn như bcrypt (nounce + pwd). Bạn có thể thích bcrypt hơn SHA1 hoặc MD5 vì nó có thể được điều chỉnh để sử dụng nhiều CPU, do đó làm cho một cuộc tấn công brute force lâu hơn.
  2. thêm hình ảnh xác thực vào biểu mẫu đăng nhập sau một vài lỗi đăng nhập (để tránh các cuộc tấn công brute-force)
  3. nếu ứng dụng của bạn có liên kết "quên mật khẩu của tôi", hãy đảm bảo rằng ứng dụng không gửi mật khẩu mới qua email, mà thay vào đó, ứng dụng sẽ gửi liên kết đến trang (được bảo mật) cho phép người dùng xác định mật khẩu mới (có thể chỉ sau khi xác nhận của một số thông tin cá nhân, chẳng hạn như ngày sinh của người dùng). Ngoài ra, nếu ứng dụng của bạn cho phép người dùng xác định mật khẩu mới, hãy đảm bảo rằng bạn yêu cầu người dùng xác nhận mật khẩu hiện tại.
  4. và rõ ràng, bảo mật biểu mẫu đăng nhập (thường bằng HTTPS) và chính các máy chủ

Với những biện pháp này, mật khẩu của người dùng của bạn sẽ được bảo vệ khá tốt trước:

  1. => tấn công từ điển ngoại tuyến
  2. => tấn công từ điển trực tiếp
  3. => tấn công từ chối dịch vụ
  4. => các kiểu tấn công!

Tất cả các biện pháp này có thể được thực hiện nhanh chóng và đóng gói khá tốt cho nỗ lực tối thiểu! +1 =)
Luke Antins

Các cuộc tấn công DOS có liên quan đến bảo mật mật khẩu không?
Arj

1
@ a12jun: nếu bạn có liên kết "quên mật khẩu của tôi" trên trang web của mình với đầu vào "đăng nhập" đơn giản và nút "vui lòng tạo mật khẩu mới và gửi cho tôi qua email", thì bất kỳ ai biết thông tin đăng nhập của bạn đều có thể buộc bạn phải thay đổi mật khẩu của mình. Nếu anh ấy tự động chạy 10 giây một lần, thì anh ấy có thể từ chối bạn truy cập vào tài khoản của mình. Nếu anh ta thực hiện điều này với hàng nghìn người dùng, anh ta có thể khiến nhiều người trong số họ không thích dịch vụ của bạn. Nguyên tắc số 3 có thể bảo vệ bạn chống lại điều này, đó là ý của tôi (nó không rõ ràng lắm, tôi phải thừa nhận). Bảo mật = Tính bảo mật, Tính toàn vẹn, Tính khả dụng .
MiniQuark

8

Vì kết quả của một hàm băm là một chuỗi byte trong phạm vi 0 đến 255 (hoặc -128 đến 127, tùy thuộc vào ký hiệu của kiểu dữ liệu 8 bit của bạn), nên việc lưu trữ nó dưới dạng một trường nhị phân thô là hợp lý nhất , vì nó là cách biểu diễn nhỏ gọn nhất và không yêu cầu thêm bước mã hóa và giải mã.

Một số cơ sở dữ liệu hoặc trình điều khiển không hỗ trợ nhiều cho các kiểu dữ liệu nhị phân, hoặc đôi khi các nhà phát triển không đủ quen thuộc với chúng để cảm thấy thoải mái. Trong trường hợp đó, việc sử dụng mã hóa nhị phân thành văn bản như Base-64 hoặc Base-85 và lưu trữ văn bản kết quả trong trường ký tự được chấp nhận.

Kích thước của trường cần thiết được xác định bởi hàm băm mà bạn sử dụng. MD5 luôn xuất ra 16 byte, SHA-1 luôn xuất ra 20 byte. Khi bạn chọn một hàm băm, bạn thường gặp khó khăn với nó, vì việc thay đổi yêu cầu đặt lại tất cả các mật khẩu hiện có. Vì vậy, việc sử dụng trường có kích thước thay đổi không mang lại cho bạn bất cứ thứ gì.


Về cách "tốt nhất" để thực hiện băm, tôi đã cố gắng cung cấp nhiều câu trả lời cho các câu hỏi SO khác về chủ đề đó:


Nếu bạn đọc kỹ câu hỏi của tôi hơn một chút, bạn sẽ thấy tôi đang tập trung hơn vào bộ nhớ thực tế về kiểu dữ liệu và không gian được phân bổ cho trường.
TheTXI

Nhưng +1 để cung cấp thêm thông tin cho những người khác có thể đến sau.
TheTXI

Đúng rồi. Dường như tôi không phải là người duy nhất còn thiếu đó;)
Erickson

4

Tôi sử dụng sha hash của tên người dùng, một hướng dẫn trong cấu hình web và mật khẩu, được lưu trữ dưới dạng varchar (40). Nếu họ muốn brute force / dictionary, họ cũng cần phải hack máy chủ web để lấy hướng dẫn. Tên người dùng sẽ phá vỡ việc tạo một bảng cầu vồng trên toàn bộ cơ sở dữ liệu nếu họ tìm thấy mật khẩu. Nếu người dùng muốn thay đổi tên người dùng của họ, tôi chỉ cần đặt lại mật khẩu cùng một lúc.

System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(
    username.ToLower().Trim(),
    ConfigurationManager.AppSettings("salt"),
    password
);

tôi đã từng sử dụng tên người dùng như thêm muối. Nhưng sau đó chúng tôi không thể đổi tên người dùng. Chúng tôi đã chuyển sang sử dụng muối với là id, hướng dẫn, sid của người dùng hoặc khóa thay thế khác.
Ian Boyd

tru, cuộc gọi tốt. theo cách này, bạn không phải đặt lại mật khẩu khi đổi tên người dùng
Shawn

3

Một hàm băm đơn giản của mật khẩu hoặc thậm chí (muối + mật khẩu) thường không đủ.

xem:

http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes/

http://gom-jabbar.org/articles/2008/12/03/why-you-should-use-bcrypt-to-store-your-passwords

Cả hai đều đề xuất các thuật toán bcrypt. Các triển khai miễn phí có thể được tìm thấy trực tuyến cho hầu hết các ngôn ngữ phổ biến.


Các liên kết tuyệt vời vượt ra ngoài các mối quan tâm bảo mật hời hợt. Đối với các thuật toán cố tình làm chậm, liệu điều quan trọng là phải tính toán các hàm băm ở phía máy khách để không làm quá tải máy chủ (có thể đã khá bận)?
cheduardo

Không hẳn vậy. Mục đích chỉ đơn giản là làm cho nó "Chậm" hơn một chút. Chỉ để cung cấp cho bạn một ý tưởng. Tôi có thể băm SHA1 khoảng 200K mật khẩu mỗi giây trên hệ thống lõi tứ. Tôi nghi ngờ có ai đó cần phải xử lý 200 nghìn lần đăng nhập đồng thời từng giây .... Vì vậy, bạn sử dụng một chức năng như PBKDF2 hoặc bcrypt để làm chậm nó xuống chỉ nói 100 băm mỗi giây (tăng dòng thời gian bạo lực lên hệ số 200).
Gerald Davis

3

Bạn có thể sử dụng nhiều hàm băm trong cơ sở dữ liệu của mình, nó chỉ cần thêm một chút nỗ lực. Tuy nhiên, điều đó rất xứng đáng nếu bạn nghĩ rằng có cơ hội từ xa bạn sẽ cần hỗ trợ các định dạng bổ sung trong tương lai. Tôi thường sử dụng các mục nhập mật khẩu như

{hashId} $ {salt} $ {hash password}

trong đó "hashId" chỉ là một số tôi sử dụng nội bộ để nhận ra điều đó, ví dụ: tôi đang sử dụng SHA1 với một mẫu băm cụ thể; "salt" là một muối ngẫu nhiên được mã hóa base64; và "mật khẩu băm" là một mã băm được mã hóa base64. Nếu bạn cần di chuyển hàm băm, bạn có thể chặn mọi người bằng định dạng mật khẩu cũ và yêu cầu họ thay đổi mật khẩu vào lần đăng nhập tiếp theo.

Như những người khác đã đề cập, bạn muốn cẩn thận với hàm băm của mình vì rất dễ làm điều gì đó không thực sự an toàn, ví dụ: H (muối, mật khẩu) yếu hơn nhiều so với H (mật khẩu, muối), nhưng đồng thời bạn cũng muốn cân bằng nỗ lực dành cho việc này với giá trị của nội dung trang web. Tôi sẽ thường sử dụng H (H (mật khẩu, muối), mật khẩu).

Cuối cùng, chi phí của việc sử dụng mật khẩu được mã hóa base64 là khiêm tốn khi so sánh với lợi ích của việc có thể sử dụng các công cụ khác nhau mong đợi dữ liệu văn bản. Vâng, chúng sẽ linh hoạt hơn, nhưng bạn đã sẵn sàng nói với sếp của mình rằng ông ấy không thể sử dụng công cụ bên thứ ba yêu thích của mình vì bạn muốn tiết kiệm một vài byte mỗi bản ghi không? :-)

Đã chỉnh sửa để thêm một nhận xét khác: nếu tôi đề nghị cố tình sử dụng một thuật toán đốt cháy ngay cả 1/10 giây băm mỗi mật khẩu, tôi sẽ may mắn chỉ bị cười ra khỏi văn phòng của sếp. (Không may mắn như vậy? Anh ấy sẽ ghi lại điều gì đó để thảo luận trong bài đánh giá hàng năm tiếp theo của tôi.) Đốt cháy thời gian đó không phải là vấn đề khi bạn có hàng chục, thậm chí hàng trăm người dùng. Nếu bạn đang thúc đẩy 100k người dùng, bạn thường sẽ có nhiều người đăng nhập cùng một lúc. Bạn cần một cái gì đó nhanh và mạnh, không phải chậm và mạnh. "Nhưng còn thông tin thẻ tín dụng thì sao?" tốt nhất là không cần thiết vì thông tin thẻ tín dụng được lưu trữ không nên ở bất kỳ đâu gần cơ sở dữ liệu thông thường của bạn và sẽ được mã hóa bởi ứng dụng, không phải người dùng cá nhân.


Không có cái gọi là nhanh và mạnh khi nói đến băm. Lấy làm tiếc. Nếu nó là nhanh cho bạn thì nó là nhanh cho một kẻ tấn công vũ phu. Sử dụng hàm dẫn xuất khóa là một phương pháp hợp lệ để tăng cường mật khẩu.
Gerald Davis

2

Nếu bạn đang làm việc với ASP.Net, bạn có thể sử dụng API thành viên tích hợp sẵn.

Nó hỗ trợ nhiều loại tùy chọn lưu trữ, nhúng vào; băm một chiều, mã hóa hai chiều, md5 + muối. http://www.asp.net/learn/security để biết thêm thông tin.

Nếu bạn không cần bất cứ thứ gì quá cầu kỳ, điều này rất tốt cho các trang web.

Nếu bạn không sử dụng ASP.Net, đây là một liên kết tốt đến một vài bài báo từ 4guys và codeproject

http://aspnet.4guysfromrolla.com/articles/081705-1.aspx http://aspnet.4guysfromrolla.com/articles/103002-1.aspx http://www.codeproject.com/KB/security/SimpleEncryption. aspx


2

Vì câu hỏi của bạn là về phương pháp và kích thước lưu trữ, tôi sẽ giải quyết vấn đề đó.

Kiểu lưu trữ có thể là dạng nhị phân hoặc dạng văn bản (base64 là phổ biến nhất). Nhị phân nhỏ hơn nhưng tôi thấy làm việc với văn bản dễ dàng hơn. Nếu bạn đang thực hiện ướp muối cho mỗi người dùng (mỗi mật khẩu khác nhau) thì việc lưu trữ muối + băm dưới dạng một chuỗi kết hợp sẽ dễ dàng hơn.

Kích thước phụ thuộc vào thuật toán băm. Đầu ra của MD5 luôn là 16 byte, SHA1 luôn là 20 byte. SHA-256 & SHA-512 lần lượt là 32 & 64 byte. Nếu bạn đang sử dụng mã hóa văn bản, bạn sẽ cần nhiều dung lượng hơn một chút tùy thuộc vào phương pháp mã hóa. Tôi có xu hướng sử dụng Base64 vì dung lượng lưu trữ tương đối rẻ. Base64 sẽ yêu cầu trường lớn hơn khoảng 33%.

Nếu bạn có mỗi người dùng muối, bạn cũng sẽ cần không gian cho băm. Đặt tất cả lại với nhau 64 bit salt + SHA1 hash (160 bit) base64 được mã hóa có 40 ký tự nên tôi lưu trữ nó dưới dạng char (40).

Cuối cùng, nếu bạn muốn làm đúng, bạn không nên sử dụng một hàm băm duy nhất mà là một hàm dẫn xuất khóa như RBKDF2. Hàm băm SHA1 và MD5 rất nhanh. Thậm chí một ứng dụng luồng đơn có thể băm khoảng 30K đến 50K mật khẩu mỗi giây, tương đương với 200K mật khẩu mỗi giây trên máy lõi tứ. GPU có thể băm nhiều mật khẩu từ 100x đến 1000x mỗi giây. Với tốc độ như vậy, tấn công vũ phu trở thành một phương pháp xâm nhập có thể chấp nhận được. RBKDF2 cho phép bạn chỉ định số lần lặp để tinh chỉnh mức độ "chậm" của quá trình băm của bạn. Vấn đề không phải là đưa hệ thống đến đầu gối của nó mà là chọn một số lần lặp lại để bạn giới hạn giới hạn trên của thông lượng băm (giả sử 500 băm mỗi giây). Phương pháp chứng minh trong tương lai sẽ là bao gồm số lần lặp lại trong trường mật khẩu (số lần lặp + muối + băm). Điều này sẽ cho phép tăng số lần lặp lại trong tương lai để bắt kịp với các bộ xử lý mạnh hơn. Để linh hoạt hơn nữa, hãy sử dụng varchar để cho phép các hàm băm có khả năng lớn hơn / thay thế trong tương lai.

Triển khai .Net là RFC2892DeriveBytes http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

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.