如何从数据库中储存和使用shiro's盐[英] How to stock and use a shiro's salt from database

本文是小编为大家收集整理的关于如何从数据库中储存和使用shiro's盐的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我在身份验证中使用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);
}

我在数据库中将盐储存.现在,在我的领域中,我想从数据库中获取数据,我为此使用了交易服务.但是我的盐很强壮,所以我希望它以静态方法为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();    
}

感谢您的帮助.

推荐答案

,如出色的答案中所述 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=

私人盐未存储在数据库中,如果对手获得了对数据库转储的访问,则很难破解密码.

使用shiro-1.2.2

创建了此示例

感谢 shiro.ini

的语法帮助

其他推荐答案

您是否查看了密码绘制器/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);
}

然后,您只需将密码匹配程序用作领域中的匹配器.

realm.setCredentialsMatcher(new PasswordMatcher());

或shiro.ini:

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

其他推荐答案

DefaultPasswordservice实现会自动将随机盐添加到每个encryptpassword调用中.该"公共"盐将存储在您从" EncryptPassword"中收到的" HashedPasswordbase64"中.

因为每个哈希密码都不会单独生成"公共"盐,因此不能简单地"生成彩虹桌,并立即生成所有散布密码.对于每个哈希密码,攻击者必须生成一个独特的彩虹桌,因为唯一的"公共"盐.到目前为止,您不需要在数据库中添加额外的盐.

为了使您的存储的哈希密码更加安全,您可以添加应该存储在其他任何地方的"私人"盐 - 只要不在数据库中即可.通过使用"私人"盐,您可以保护哈希密码免受蛮力的彩虹桌攻击,因为攻击者不知道"私人"盐,也无法从数据库条目中获得"私人"盐.

这是一个非常基本的示例,如何创建使用"私有"盐作为恒定字符串的"私有"盐,并且可以用作corltentialsmatcher:

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

然后,您可以在shiro.ini中使用自己的实现:

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

使用shiro-1.2.2

创建了此示例

本文地址:https://www.itbaoku.cn/post/597744.html

问题描述

I use shiro in application for the authenticate. I use hashed password with a salt and I store them in my database like this :

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

I store the salt with a String in my database. Now in my realm I want to get back my datas from the database, I use a transactionnal service for this. But my salt is a Strong so I want it to turn back as ByteSource type with the static method :

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

But when I create my SaltedAuthenticationInfo it doesn't auth.

I think my problem is from my convert method :

private String byteArrayToHexString(byte[] bArray){

        StringBuffer buffer = new StringBuffer();

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

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

Thanks for your help.

推荐答案

As mentioned in the excellent answer https://stackoverflow.com/a/20206115/603901, Shiro's DefaultPasswordService already generates unique salts for each password.

However, there is no need to implement a custom PasswordService to add a private salt (sometimes called "pepper") to the per-user salts. Private salt can be configured in 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 code for generating a matching password hash:

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

The resulting hash looks like this:

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

The private salt is not stored in the database, which makes it harder to crack the passwords if an adversary gains access to a database dump.

This example was created using shiro-1.2.2

Thanks to https://github.com/Multifarious/shiro-jdbi-realm/blob/master/src/test/resources/shiro.ini for help with the syntax for shiro.ini

其他推荐答案

Have you looked at PasswordMatcher / PasswordService?

This already has all of the encoding/decoding/compare logic built-in. To use it:

Storing password in database:

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

Then you can simply use PasswordMatcher as the matcher in your realm.

realm.setCredentialsMatcher(new PasswordMatcher());

or in shiro.ini:

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

其他推荐答案

The DefaultPasswordService implementation automatically adds a random salt to each encryptPassword call. That "public" salt will be stored within the "hashedPasswordBase64" that you receive from "encryptPassword".

Because the "public" salt is individually generated for each hashed password one cannot "simply" generate a rainbow table and brute-force all your hashed passwords at once. For each hashed password the attacker would have to generate an own, unique rainbow table because of the unique "public" salt. So far you do not need to put an extra salt into the database.

To make your stored hashed passwords even more secure you can furthermore add a "private" salt that should be stored anywhere else - as long as not in the database. By using a "private" salt you could protect the hashed passwords against a brute-force rainbow-table attack, because the attacker does not know the "private" salt and cannot gain the "private" salt from the database entries.

This is a very basic example how to create a PasswordService that utilizes a "private" salt provided as a constant string and that works as CredentialsMatcher:

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

you then could use your own implementation in shiro.ini:

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

This example was created using shiro-1.2.2