2012-09-19 34 views
8

Tôi sử dụng shiro trong ứng dụng để xác thực. Tôi sử dụng mật khẩu băm với muối và tôi lưu trữ chúng trong cơ sở dữ liệu của mình như sau:Làm thế nào để trữ và sử dụng muối của shiro từ cơ sở dữ liệu

private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){ 

    ByteSource salt = randomNumberGenerator.nextBytes(32); 

    byte[] byteTabSalt = salt.getBytes(); 

    String strSalt = byteArrayToHexString(byteTabSalt); 

    String hashedPasswordBase64 = new Sha256Hash(inPassword, salt, 1024).toBase64(); 

    return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt); 
} 

Tôi lưu trữ muối bằng một chuỗi trong cơ sở dữ liệu của tôi. Bây giờ trong lĩnh vực của tôi, tôi muốn lấy lại dữ liệu của tôi từ cơ sở dữ liệu, tôi sử dụng một dịch vụ transactionnal cho việc này. Nhưng muối của tôi là một mạnh mẽ vì vậy tôi muốn nó quay lưng as type ByteSource với phương pháp tĩnh:

ByteSource byteSourceSalt = Util.bytes(salt); //where the salt is a String 

Nhưng khi tôi tạo của tôi SaltedAuthenticationInfo nó không auth.

Tôi nghĩ rằng vấn đề của tôi là từ phương pháp chuyển đổi của tôi:

private String byteArrayToHexString(byte[] bArray){ 

     StringBuffer buffer = new StringBuffer(); 

     for(byte b : bArray) { 
      buffer.append(Integer.toHexString(b)); 
      buffer.append(" "); 
     } 

return buffer.toString().toUpperCase();  
} 

Nhờ sự giúp đỡ của bạn.

Trả lời

13

Như đã đề cập trong câu trả lời tuyệt vời https://stackoverflow.com/a/20206115/603901, DefaultPasswordService Shiro của đã tạo muối duy nhất cho mỗi mật khẩu.

Tuy nhiên, không cần triển khai PasswordService tùy chỉnh để thêm muối riêng (đôi khi được gọi là "hạt tiêu") vào muối của mỗi người dùng. muối tư nhân có thể được cấu hình trong shiro.ini:

[main] 
hashService = org.apache.shiro.crypto.hash.DefaultHashService 
hashService.hashIterations = 500000 
hashService.hashAlgorithmName = SHA-256 
hashService.generatePublicSalt = true 
# privateSalt needs to be base64-encoded in shiro.ini but not in the Java code 
hashService.privateSalt = myVERYSECRETBase64EncodedSalt 
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher 

passwordService = org.apache.shiro.authc.credential.DefaultPasswordService 
passwordService.hashService = $hashService 
passwordMatcher.passwordService = $passwordService 

mã Java để tạo ra một hash mật khẩu phù hợp:

DefaultHashService hashService = new DefaultHashService(); 
hashService.setHashIterations(HASH_ITERATIONS); // 500000 
hashService.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME); 
hashService.setPrivateSalt(new SimpleByteSource(PRIVATE_SALT)); // Same salt as in shiro.ini, but NOT base64-encoded. 
hashService.setGeneratePublicSalt(true); 

DefaultPasswordService passwordService = new DefaultPasswordService(); 
passwordService.setHashService(hashService); 
String encryptedPassword = passwordService.encryptPassword("PasswordForThisUser"); 

Các băm kết quả trông như thế này:

$shiro1$SHA-256$500000$An4HRyqMJlZ58utACtyGDQ==$nKbIY9Nd9vC89G4SjdnDfka49mZiesjWgDsO/4Ly4Qs= 

Muối tin không được lưu trữ trong cơ sở dữ liệu, điều này làm cho việc crack các mật khẩu trở nên khó khăn hơn nếu một đối thủ có quyền truy cập vào một kết xuất cơ sở dữ liệu.

Ví dụ này được tạo bằng shiro-1.2.2

Nhờ https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini để được giúp đỡ với cú pháp cho shiro.ini

+1

làm thế nào tôi có thể nhận được tự động muối công cộng được tạo ra bởi shiro để lưu trữ nó vào cột tách trong db – thoitbk

4

Bạn đã xem PasswordMatcher/PasswordService chưa?

Điều này đã có tất cả mã hóa/giải mã/so sánh logic được tích hợp sẵn. Để sử dụng nó:

Lưu trữ mật khẩu trong cơ sở dữ liệu:

PasswordService service = new DefaultPasswordService(); // or use injection or shiro.ini to populate this 

private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){ 

    String hashedPasswordBase64 = service.encryptPassword(inPassword); 

    return new User(inName,inFirstName,inLastName,hashedPasswordBase64,strSalt); 
} 

Sau đó, bạn chỉ có thể sử dụng PasswordMatcher như các khớp trong lĩnh vực của bạn.

realm.setCredentialsMatcher(new PasswordMatcher()); 

hoặc trong shiro.ini:

matcher = org.apache.shiro.authc.credential.PasswordMatcher 
realm.credentialsMatcher = $matcher 
+4

Ok, cảm ơn vì câu trả lời của bạn. Tôi sẽ thử cái này. Nhưng tôi không hiểu tôi phải sử dụng muối ở đâu và liên kết giữa mật khẩu và muối ở đâu. – Fred37b

1

tôi thay đổi loại của tôi cho tiết kiệm muối của tôi. Bây giờ tôi đang sử dụng một byte [] thay vì một String.

ByteSource salt = randomNumberGenerator.nextBytes(32); 

byte[] byteTabSalt = salt.getBytes(); 

Và tôi lưu trữ byteTabSalt trong cơ sở dữ liệu của mình.

4

Việc triển khai DefaultPasswordService tự động thêm một muối ngẫu nhiên vào mỗi lệnh gọi mật mã. Muối "công khai" này sẽ được lưu trữ trong "hashedPasswordBase64" mà bạn nhận được từ "encryptPassword".

Vì muối "công khai" được tạo riêng cho mỗi mật khẩu băm, bạn không thể "đơn giản" tạo bảng cầu vồng và bạo lực tất cả mật khẩu băm cùng một lúc. Đối với mỗi mật khẩu băm, kẻ tấn công sẽ phải tạo ra một bảng cầu vồng riêng, độc đáo vì muối "công cộng" duy nhất. Cho đến nay bạn không cần phải thêm một muối vào cơ sở dữ liệu.

Để làm cho mật khẩu băm được lưu trữ của bạn an toàn hơn, bạn có thể thêm muối "riêng tư" sẽ được lưu trữ ở bất kỳ nơi nào khác - miễn là không có trong cơ sở dữ liệu. Bằng cách sử dụng muối "riêng", bạn có thể bảo vệ mật khẩu băm chống lại cuộc tấn công bằng bảng cầu vồng, bởi vì kẻ tấn công không biết muối "riêng tư" và không thể nhận được muối "riêng tư" từ các mục cơ sở dữ liệu.

Đây là một ví dụ rất cơ bản làm thế nào để tạo ra một PasswordService rằng sử dụng một "private" muối cung cấp như là một chuỗi liên tục và làm việc như CredentialsMatcher:

public class MyPrivateSaltingPasswortService extends DefaultPasswordService 
{ 
    public MyPrivateSaltingPasswortService() 
    { 
     super(); 
     HashService service = getHashService(); 
     if (service instanceof DefaultHashService) 
     { 
     ((DefaultHashService) service).setPrivateSalt(
      new SimpleByteSource("MySuperSecretPrivateSalt")); 
     } 
    } 
} 

sau đó bạn có thể sử dụng thực hiện của riêng bạn trong shiro.ini:

[main] 
saltedService = com.mycompany.MyPrivateSaltingPasswortService 
matcher = org.apache.shiro.authc.credential.PasswordMatcher 
matcher.passwordService = $saltedService 
realm.credentialsMatcher = $matcher 

Ví dụ này được tạo bằng shiro-1.2.2

+0

Bạn có thể giải thích: "Việc triển khai DefaultPasswordService tự động thêm một muối ngẫu nhiên vào mỗi cuộc gọi encryptPassword. Muối" công khai "đó sẽ được lưu trữ trong" hashedPasswordBase64 "mà bạn nhận được từ" encryptPassword "."? Tôi không hiểu phải muối công cộng này được lưu trong cột riêng biệt (không phải cột mật khẩu)? –

+0

Cho đến nay bạn không cần phải bỏ thêm muối vào cơ sở dữ liệu. - Ý anh là gì? –

+1

Xin chào Pasha, mã thông báo đã tạo chứa một số khối thông tin khác nhau. một trong những khối này là muối công cộng nên Shiro có thể băm lại và thử lại mật khẩu do người dùng nhập lại. miễn là bạn lưu trữ các mã thông báo được tạo ra "như là" bạn không cần phải lưu trữ các muối công cộng - bạn thậm chí không biết nó bởi vì Shiro chăm sóc nó. Hãy xem câu trả lời từ Mikael Falkvidd - có một ví dụ về mã thông báo được tạo và cũng là một tùy chọn để xác định một muối riêng. – seafoxx

Các vấn đề liên quan