Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何储存和使用shiro';s salt来自数据库_Java_Database_Salt_Shiro - Fatal编程技术网

Java 如何储存和使用shiro';s salt来自数据库

Java 如何储存和使用shiro';s salt来自数据库,java,database,salt,shiro,Java,Database,Salt,Shiro,我在应用程序中使用shiro进行身份验证。我将哈希密码与salt一起使用,并将其存储在数据库中,如下所示: private User createUserWithHashedPassword(String inName, String inFirstName, String inLastName, String inPassword){ ByteSource salt = randomNumberGenerator.nextBytes(32); byte[] byt

我在应用程序中使用shiro进行身份验证。我将哈希密码与salt一起使用,并将其存储在数据库中,如下所示:

    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);
}
我用字符串将盐存储在数据库中。现在在我的领域中,我想从数据库中获取数据,为此我使用transactionnal服务。但是我的salt是一个强类型,所以我希望它使用静态方法返回为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();    
}

谢谢你的帮助。

你看过密码匹配器/密码服务吗

这已经内置了所有编码/解码/比较逻辑。要使用它:

在数据库中存储密码:

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
[main]
saltedService = com.mycompany.MyPrivateSaltingPasswortService
matcher = org.apache.shiro.authc.credential.PasswordMatcher
matcher.passwordService = $saltedService
realm.credentialsMatcher = $matcher
[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

为了节省盐,我改变了我的类型。现在我使用字节[]而不是字符串

ByteSource salt  = randomNumberGenerator.nextBytes(32);

byte[] byteTabSalt  = salt.getBytes();

我在数据库中存储byteTabSalt。

DefaultPasswordService实现会自动为每个encryptPassword调用添加一个随机salt。该“公共”salt将存储在从“encryptPassword”接收的“hashedPasswordBase64”中


因为“公共”salt是为每个散列密码单独生成的,所以不能“简单地”生成一个rainbow表并一次强制执行所有散列密码。对于每个散列密码,攻击者必须生成一个自己的、唯一的彩虹表,因为该表具有唯一的“公共”salt。到目前为止,您不需要在数据库中添加额外的盐

为了使您存储的哈希密码更加安全,您还可以添加一个“私有”salt,该salt应该存储在其他任何地方,只要不存储在数据库中。通过使用“私有”salt,您可以保护哈希密码免受暴力彩虹表攻击,因为攻击者不知道“私有”salt,并且无法从数据库条目中获取“私有”salt

这是如何创建密码服务的一个非常基本的示例,该服务使用作为常量字符串提供的“private”salt,并充当CredentialsMatcher:

public class MyPrivateSaltingPasswortService extends DefaultPasswordService
{
   public MyPrivateSaltingPasswortService()
   {
      super();
      HashService service = getHashService();
      if (service instanceof DefaultHashService)
      {
         ((DefaultHashService) service).setPrivateSalt(
             new SimpleByteSource("MySuperSecretPrivateSalt"));
      }
   }
}
然后,您可以在shiro.ini中使用自己的实现:

matcher = org.apache.shiro.authc.credential.PasswordMatcher
realm.credentialsMatcher = $matcher
[main]
saltedService = com.mycompany.MyPrivateSaltingPasswortService
matcher = org.apache.shiro.authc.credential.PasswordMatcher
matcher.passwordService = $saltedService
realm.credentialsMatcher = $matcher
[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

这个例子是使用shiro-1.2.2创建的,正如优秀答案中提到的,shiro的DefaultPasswordService已经为每个密码生成了唯一的salt

但是,不需要实现自定义密码服务来向每个用户的salt添加私有salt(有时称为“pepper”)。可以在shiro.ini中配置专用盐:

matcher = org.apache.shiro.authc.credential.PasswordMatcher
realm.credentialsMatcher = $matcher
[main]
saltedService = com.mycompany.MyPrivateSaltingPasswortService
matcher = org.apache.shiro.authc.credential.PasswordMatcher
matcher.passwordService = $saltedService
realm.credentialsMatcher = $matcher
[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=
私有salt不存储在数据库中,这使得当对手获得对数据库转储的访问权限时,破解密码变得更加困难

此示例是使用shiro-1.2.2创建的


感谢您对shiro.ini语法的帮助

好的,谢谢您的回答。我试试这个。但是我不明白我现在必须在哪里使用我的salt,密码和salt之间的链接在哪里。请解释一下:“DefaultPasswordService实现会自动向每个encryptPassword调用添加一个随机salt。该“公共”salt将存储在从“encryptPassword”接收的“hashedPasswordBase64”中。”?我不明白这个公共salt必须保存在单独的列中(不是密码列)?到目前为止,您不需要在数据库中添加额外的salt。-您好,Pasha,生成的令牌包含几个不同的信息块。其中一个模块是公共salt,因此Shiro可以重新散列并再次测试用户输入的密码。只要你将生成的代币“按原样”存储,你就不需要存储公共盐——你甚至不需要知道它,因为Shiro会处理它。请看一下Mikael Falkvidd的答案-这里有一个生成令牌的示例,还有一个定义私有salt的选项。谢谢。我明白了。我怎样才能得到shiro自动生成的公共盐,以便将其存储到db中的独立列中