2012-09-19 26 views
8

我在申請認證時使用shiro。我使用哈希密碼與鹽和我將它們存儲在我的數據庫是這樣的:如何從數據庫庫存和使用shiro的鹽

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); 
} 

我店將鹽與在我的數據庫的String。現在在我的領域,我想從數據庫中取回數據,我爲此使用了一個transactionnal服務。但我的鹽是一個強大的,所以我希望它與靜態方法回頭爲ByteSource類型:

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

但是當我創造我SaltedAuthenticationInfo不權威性。

我想我的問題是從我的轉換方法:

private String byteArrayToHexString(byte[] bArray){ 

     StringBuffer buffer = new StringBuffer(); 

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

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

感謝您的幫助。

回答

13

正如優秀的答案https://stackoverflow.com/a/20206115/603901提到,Shiro的DefaultPasswordService已經生成每個密碼是唯一的鹽產生。

但是,不需要實施自定義密碼服務以向每個用戶鹽添加私有鹽(有時稱爲「胡椒」)。私人鹽可以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 
用於生成匹配的密碼散列

Java代碼:

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"); 

所得散列看起來像這樣:

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

私人鹽沒有存儲在數據庫中,這使得攻擊者獲得對數據庫轉儲的訪問時難以破解密碼。

這個例子是使用創建四郎-1.2.2

感謝https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini與語法幫助shiro.ini

+1

如何獲得由shiro生成的公共salt auto以便將其存儲到db中的分隔列 – thoitbk

4

你看過PasswordMatcher/PasswordService嗎?

這已經包含了所有內置的編碼/解碼/比較邏輯。在數據庫

存儲密碼:要使用它

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); 
} 

然後,你可以簡單地使用PasswordMatcher在你的領域的匹配。

realm.setCredentialsMatcher(new PasswordMatcher()); 

或shiro.ini:

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

好,感謝您的回答。我會試試這個。但我不明白我現在必須使用我的鹽,密碼和鹽之間的關係在哪裏。 – Fred37b

1

更改我的類型保存我的鹽。現在我正在使用byte []而不是String。

ByteSource salt = randomNumberGenerator.nextBytes(32); 

byte[] byteTabSalt = salt.getBytes(); 

而且我在我的數據庫中存儲了byteTabSalt。

4

DefaultPasswordService實現自動爲每個encryptPassword調用添加一個隨機salt。該「公共」salt將存儲在您從「encryptPassword」收到的「hashedPasswordBase64」中。

因爲對於每個哈希密碼都單獨生成「公共」salt,所以不能「簡單地」生成彩虹表,並且一次性強制所有哈希密碼。對於每個哈希密碼,由於獨特的「公共」鹽分,攻擊者必須生成自己獨特的彩虹表。到目前爲止,您不需要在數據庫中添加額外的鹽。

爲了讓您的存儲哈希密碼更安全,您還可以添加一個「私人」鹽,應該存儲在任何其他地方 - 只要不在數據庫中。通過使用「私人」鹽,你可以保護哈希密碼免受暴力彩虹表攻擊,因爲攻擊者不知道「私有」鹽,並且不能從數據庫條目中獲得「私有」鹽。

這是一個非常基本的例子,如何創建使用作爲一個常量字符串提供了一個「私人」鹽PasswordService和工作原理CredentialsMatcher:

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

你然後可以使用自己的實施四郎。INI:

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

這個例子是使用四郎-1.2.2

+0

您能否解釋一下:「DefaultPasswordService實現會自動爲每個encryptPassword調用添加一個隨機salt,該」public「salt將存儲在您從」encryptPassword「中收到的」hashedPasswordBase64「中。我不明白這個公共鹽必須保存在單獨的列(不是密碼欄)嗎? – 2014-11-08 20:15:58

+0

到目前爲止,您不需要在數據庫中添加額外的鹽。 - 你在這裏意味着什麼? – 2014-11-08 20:45:32

+1

Hello Pasha,生成的令牌包含幾個不同的信息塊。其中一個塊是公共鹽,因此Shiro可以重新散列並再次測試用戶輸入的密碼。只要您將生成的令牌「按原樣」存儲起來,則不需要存儲公共食鹽 - 因爲Shiro會照顧它,所以您甚至不知道它。請看一下Mikael Falkvidd的答案 - 這裏有一個生成的令牌的例子,也是一個定義私有鹽的選項。 – seafoxx

相關問題