How to stock and use a shiro's salt from database

前端 未结 4 525
余生分开走
余生分开走 2021-02-06 06:44

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 createUserWithHas         


        
相关标签:
4条回答
  • 2021-02-06 07:23

    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

    0 讨论(0)
  • 2021-02-06 07:29

    I change my type for the save of my salt. Now I'm using a byte[] instead of a String.

    ByteSource salt  = randomNumberGenerator.nextBytes(32);
    
    byte[] byteTabSalt  = salt.getBytes();
    

    And I stock the byteTabSalt in my database.

    0 讨论(0)
  • 2021-02-06 07:32

    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

    0 讨论(0)
  • 2021-02-06 07:42

    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
    
    0 讨论(0)
提交回复
热议问题