2012-11-15 40 views
9

Tôi mới sử dụng C# và đây là câu hỏi đầu tiên của tôi ở đây vì vậy tôi xin lỗi trước vì bất kỳ vi phạm giả mạo nào.Xác nhận hàm băm muối

Bối cảnh:

Khi đăng ký sử dụng tôi gọi phương thức CreateSaltedHash() và vượt qua nó người sử dụng đầu vào mật khẩu từ các trường văn bản. Phương thức này salts và băm mật khẩu trước khi lưu trữ nó trong cột Password trong bảng User của tôi.

Câu hỏi:

Làm thế nào tôi nên xác nhận lại mật khẩu khi người dùng cố gắng đăng nhập?

Nếu tôi gọi phương thức CreateSaltedHash() một lần nữa nó sẽ không khớp với muối ngẫu nhiên.

Tôi có nên lưu trữ các muối trong một cột riêng biệt không? Tôi có nên sử dụng dấu phân cách khi tạo hàm băm muối không? Cách an toàn nhất để xác nhận mật khẩu đầu vào dựa vào mật khẩu muối và băm là gì?

Mã số: Đây là những gì tôi có cho đến nay.

public class PasswordHash 
{ 
    public const int SALT_BYTES = 32; 

    /* 
    * Method to create a salted hash 
    */ 
    public static byte[] CreateSaltedHash(string password) 
    { 
     RNGCryptoServiceProvider randromNumberGenerator = new RNGCryptoServiceProvider(); 
     byte[] salt = new byte[SALT_BYTES]; 
     randromNumberGenerator.GetBytes(salt); 
     HashAlgorithm hashAlgorithm = new SHA256Managed(); 
     byte[] passwordByteArray = Encoding.UTF8.GetBytes(password); 
     byte[] passwordAndSalt = new byte[passwordByteArray.Length + SALT_BYTES]; 
     for (int i = 0; i < passwordByteArray.Length; i++) 
     { 
      passwordAndSalt[i] = passwordByteArray[i]; 
     } 
     for (int i = 0; i < salt.Length; i++) 
     { 
      passwordAndSalt[passwordByteArray.Length + i] = salt[i]; 
     } 
     return hashAlgorithm.ComputeHash(passwordAndSalt); 
    } 

    public static bool OkPassword(string password) 
    { 
     //This is where I want to validate the password before logging in. 
    } 
} 


Gọi phương thức trong lớp ký.

User user= new User(); 
user.password = PasswordHash.CreateSaltedHash(TextBoxUserPassword.Text); 
+0

'Tôi có nên lưu trữ muối trong cột riêng biệt' - Có. Sau đó tham chiếu đến điều đó. – TheGeekZn

+0

Bạn có hiểu rằng có một vấn đề nghiêm trọng với phương pháp của bạn phải không? Bạn thực sự cần phải sử dụng một thiết kế thuật toán hasing để bảo mật mật khẩu mà lựa chọn hiện tại của bạn không phải là một lựa chọn tốt. –

+0

Tôi đã chỉnh sửa tiêu đề của bạn. Vui lòng xem, "[Câu hỏi có nên bao gồm" thẻ "trong tiêu đề của họ không?] (Http://meta.stackexchange.com/questions/19190/)", trong đó sự đồng thuận là "không, họ không nên". –

Trả lời

1

Khi bạn tạo băm lần đầu tiên, bạn cần lưu trữ cả muối và băm cuối cùng - sau đó sử dụng lại cùng một muối để so sánh trong tương lai.

Vì vậy, bạn thay đổi phương thức CreateSaltedHash để lấy mật khẩu và muối và viết phương thức CreateSalt mới để tạo muối khi mật khẩu được tạo/thay đổi được lưu trữ cùng với băm cuối cùng.

0

Tôi có nên lưu trữ muối trong một cột riêng biệt không?

Có.

Tôi có nên sử dụng dấu phân cách khi tạo hàm băm muối không?

Không cần thiết, nhưng nó cũng sẽ không bị tổn thương miễn là bạn bao gồm cùng một dấu phân cách khi xác thực.

Cách an toàn nhất để xác thực mật khẩu đầu vào dựa vào mật khẩu được nhập bằng muối và băm là gì?

SHA512, SHA-2 hoặc -3 sẽ an toàn hơn SHA256, nhưng bạn có cần bảo mật hơn nhiều không?

0

Bạn có thể lưu trữ các muối, hoặc sử dụng muối cùng mỗi lần. Tôi khuyên bạn nên lưu trữ muối vì nó an toàn hơn so với sử dụng cùng một muối trên tất cả người dùng.

Hầu hết các bảng của tôi có một cột có ngày giờ khi hàng được tạo. Tôi sử dụng thuộc tính Ticks của cấu trúc DateTime giá trị này để làm băm nhỏ hàm băm, nhưng bạn có thể sử dụng bất kỳ thứ gì bạn thích, miễn là bạn sử dụng cùng một muối cho người dùng mỗi lần. Một điều cần chú ý là nếu bạn sử dụng phương thức này, và bạn đang sử dụng kiểu DateTime của SQL (và không phải DateTime2), thì có một vấn đề chính xác. Nếu bạn tạo mã số DateTime, bạn sẽ cần phải cắt bớt nó (tôi tin là hàng trăm giây).

0

Và để có câu trả lời dài hơn -

Điều này phải là ngẫu nhiên với mọi mật khẩu được tạo. Điều này sẽ làm cho nó độc đáo trong chính nó. Do 'ngẫu nhiên' này, bạn hầu như không bao giờ có thể tìm kiếm băm liên quan đến tệp một cách có lập trình.

Cách bạn mã hóa mật khẩu (không có mã băm) phải giống nhau, vì vậy việc sử dụng phương pháp này ngược lại sẽ là đủ mỗi lần.
PS: (Một cách an toàn hơn o xác nhận) Bạn có thể đảo ngược các mật khẩu được mã hóa để ban đầu của nó [Khó], hoặc mã hóa mật khẩu xác nhận với băm, và chắc chắn rằng mật khẩu được mã hóa khớp với lưu trong DB [Ưa thích].

Vì vậy, bạn sẽ cần lưu trữ mật khẩu được mã hóa, cũng như mã băm được liên kết với nó, trong cơ sở dữ liệu.

Đây sẽ là cách thu thập tất cả thông tin cần thiết để xác thực mật khẩu.

0

Vì bạn đang tạo ra một muối ngẫu nhiên, bạn sẽ cần phải lưu trữ muối trên cơ sở dữ liệu. Vấn đề với điều đó là nếu cơ sở dữ liệu của bạn bị xâm nhập, kẻ tấn công sẽ có muối và mật khẩu băm, để họ có thể dễ dàng xác định mật khẩu thực. Lý tưởng nhất là bạn nên có một muối tĩnh trong mã của bạn để nếu cơ sở dữ liệu của bạn bị xâm phạm, chúng vẫn không có muối và nếu mã của bạn bị xâm phạm, chúng chưa có cơ sở dữ liệu.

Một giải pháp khác có thể là sử dụng hạt tiêu. Pepper tương tự như muối nhưng bạn không lưu trữ cơ sở dữ liệu bằng muối và mật khẩu băm. Nó sẽ được lưu trữ trong mã. Bằng cách này bạn có một muối ngẫu nhiên được tạo ra và một hằng số được lưu trữ riêng biệt. Để làm cho hạt tiêu ngẫu nhiên hơn, bạn có thể tạo một chuỗi con của một chuỗi lớn hơn mà bạn đang sử dụng cho một hạt tiêu được bù đắp dựa trên một số biến, chẳng hạn như id người dùng. Điều này một lần nữa là một điều nội bộ mà một cuộc tấn công sẽ không biết nếu họ quản lý để có được dữ liệu của bạn.

+1

Nếu bạn có một muối khác nhau, duy nhất cho mỗi mật khẩu, sau đó nó trở nên khó khăn hơn cho một hacker để crack nhiều passords. – Polyfun

+0

Có nhưng bạn cần phải lưu trữ các muối duy nhất ở đâu đó, nếu chúng nằm trên cơ sở dữ liệu thì hacker sẽ có chúng để thực tế là chúng khác nhau thì không liên quan. –

+3

Không phải như vậy, bởi vì nếu các muối là duy nhất, nó sẽ trở nên đắt hơn nhiều để crack nhiều mật khẩu, đặc biệt là sử dụng một cái gì đó như bcrypt - xin vui lòng xem http://www.codinghorror.com/blog/2012/04/speed-hashing.html . – Polyfun

1

Như các trạng thái câu trả lời khác; có, bạn nên lưu trữ muối hoặc lấy nó từ ví dụ tên người dùng.

Bạn cũng nên sử dụng Rfc2898DeriveBytes để đảm bảo an toàn hơn.

Đây là một bài viết tốt về chủ đề đó: Password salt and hashing in C#

3

Bạn có thể sử dụng Bcrypt.Net; nó có rất nhiều khuyến nghị để thực sự an toàn, cộng với nó rất dễ sử dụng.Như tôi đã hiểu, khi bạn tạo mật khẩu, nó sẽ tự động tạo ra một muối duy nhất cho bạn, sau đó được lưu trữ trong chuỗi mật khẩu băm; do đó bạn không lưu trữ muối riêng biệt, nhưng trong cùng một lĩnh vực như mật khẩu băm. Vấn đề là mỗi mật khẩu đều có muối riêng, điều này khiến cho nó khó khăn hơn nhiều (tốn thời gian) cho một hacker để crack nhiều mật khẩu. Các thuật toán Bcrypt sử dụng cũng là CPU chuyên sâu, do đó, nó đòi hỏi rất nhiều quyền lực tính toán (= tiền) để crack.

Jeff Atwood (người kiểm duyệt ngăn xếp) recommends Bcrypt.

0

Bạn nên lưu thông báo và muối. Các giá trị lặp lại và digestLength có thể là hằng số trong ứng dụng của bạn.

byte[] getNewSalt(Int32 size) 
{ 
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
    byte[] salt = new byte[size]; 
    rng.GetBytes(salt); 
    return salt; 
} 


byte[] getPasswordDigest(byte[] value, byte[] salt, Int32 iterations, Int32 digestLength) 
{ 
    Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(value, salt, iterations); 
    return deriveBytes.GetBytes(digestLength); 
} 

Bài viết gần đây gợi ý rằng để bảo mật hơn, bạn có thể chia mật khẩu thành nhiều phần, băm từng phần riêng lẻ, sau đó lưu chúng vào các bảng riêng trong DB.

1

Tôi đề nghị bạn sử dụng SaltedHash của ServiceStack mà bạn có thể cài đặt nó từ Nuget của bạn. Chỉ cần nhập Install-Package ServiceStack vào Bảng điều khiển Nuget của bạn, khi đó bạn sẽ có thể sử dụng các mục nhập sau trong mã của mình.

using ServiceStack.ServiceInterface.Auth; 

Và sau đó bạn sẽ tạo ra muối và băm rất nhiều dễ dàng hơn và hoàn toàn nhanh so với trước đây của bạn. Chỉ cần nhập mã sau đây:

class Security 
{ 
    ... 
    public void generate(string Password) 
    { 
    string hash, salt; 
    new SaltedHash().GetHashAndSaltString(Password,out hash,out salt); 
    //Store the hash and salt 
    } 
    ... 
} 

, Bạn phải cửa hàng băm và muối để có thể chạy Method OkPassword của bạn.

public bool OkPassword(string Password) 
{ 
    var hash = //getStoredHash 
    var salt = //getStoredSalt 
    bool verify = new SaltedHash().VerifyHashString(Password, hash , salt); 
    return verify ; 
} 
Các vấn đề liên quan