How to use Shiro SaltedAuthenticationInfo?

I am working on an authentication component for my application. I use the Apache Shiro API with a salted password.

I create a new user with salt, as in this example:

ByteSource salt = randomNumberGenerator.nextBytes(32); byte[] byteTabSalt = salt.getBytes(); String strSalt = byteArrayToHexString(byteTabSalt); String hashedPasswordBase64 = new Sha256Hash(inPassword, salt, 512).toBase64(); 

But I don’t understand how I can use salt to get around the user in the doGetAuthenticationInfo method. My method should return SaltedAuthenticatedInfo, but I don't understand how I should create it.

I do not understand the relationship between Credential Matcher and SaltedAuthenticateInfo.

Do I need to specify an account when creating password salts?

Thanks for your help.

+6
source share
2 answers

SaltedAuthenticationInfo

SaltedAuthenticationInfo is an interface. For convenience, the Shiro API provides a number of default options. If possible, try using one of the default implementations; Do not create your own. I suggest SimpleAuthenticationInfo , which implements more than just SaltedAuthenticationInfo , but will probably be enough for your purposes.
See org.apache.shiro.authc.SimpleAuthenticationInfo for more information.

If you absolutely must implement your own SaltedAuthenticationInfo , you should carefully monitor the documentation.
See org.apache.shiro.authc.AuthenticationInfo and org.apache.shiro.authc.SaltedAuthenticationInfo for more information.

HashedCredentialMatcher

boolean doCredentialsMatch(AuthenticationToken, AuthenticationInfo) actually executes the authentication logic.
This method accepts user-provided credentials in the form of AuthenticationToken and compares them with previously saved credentials in the form of AuthenticationInfo .
You have to make sure that you first pass all the necessary information to the HashCredentialMatcher , though (iterations, algorithm and salt in SaltedAuthenticationInfo ).

using a pseudo example

 final int iterations = 50000; AuthenticationToken authToken = ...; SaltedAuthenticationInfo saltedAuthInfo = ...; HashedCredentialsMatcher authenticator = new HashedCredentialsMatcher(Sha256Hash.ALGORITHM_NAME); authenticator.setHashIterations(iterations); final boolean successfulAuthentication = authenticator.doCredentialsMatch(authToken, saltedAuthInfo); 

See org.apache.shiro.authc.credential.HashedCredentialsMatcher for details.

Other safety notes

  • Salt length
    256-bit salt looks good. With a salt that is large, you minimize the risk that two users will have one salt. Keep in mind when choosing the salt that the Birthday Paradox plays.

  • Number of iterations
    Generally, you should never use less than 10,000. You are currently using 512,

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

    Most hashing algorithms are extremely fast (including sha256), you do not want any potential hackers to provide any services. The more iterations you use, the slower authentication will be, but it also slows down hacking attempts.

    You need to set the maximum possible number of iterations, while maintaining acceptable responsiveness for your application. You may be surprised how tall you can. Personally, I tend to use millions; but I'm paranoid and don't mind a little delay
    See Key Stretching for more details.

  • Personally, I would avoid hard coding any hash parameters (hash algorithm, salt size, iteration counter, etc.)
    Due to the hard coding of these values, you limit your immediate ability to adapt and respond.

    Storing these values ​​with hashed credentials allows for more dynamic authentication, where you can configure and deploy stronger algorithms in the future with relatively little effort.

    For example, your default hash algorithm might be sha256, using 50,000 iterations and a 256-bit salt. In the future, although 50,000 iterations may not be enough.
    Without any problems, you can change the preferred configuration of the algorithm to repeat 100,000 times for all new passwords. You do not need to worry about breaking old passwords, because you do not change the algorithm parameters that you saved with existing credentials. You can also use this to completely resize the salt or even the algorithm.

    If you wish, you can force everyone to change their password; forcing users to pick up a new (hopefully stronger) algorithm setting.
    The Unix operating system has done this for many years with / etc / shadow .

    It takes a little more effort, but it's worth the investment. Strong authentication is critical.

+7
source

My mistake was to incorrectly create an AuthenticationInfo that compared the AuthenticationToken. Therefore, in the doGetAuthenticationInfo method of my own domain, I do this:

 Object principal = arg0.getPrincipal(); Object credentials = arg0.getCredentials(); String realmName = this.getName(); // to get the realm name SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, credentials, realmName); CredentialsMatcher credentialsMatcher = this.getCredentialsMatcher(); boolean successfulAuthentication = credentialsMatcher.doCredentialsMatch(arg0, simpleAuthenticationInfo); 

And therefore, logical successful authentication is correct. But I don’t understand what is the difference between CredentialsMatcher and HashedCredentialsMatcher, because this one was false. I have to read Javadok.

0
source

Source: https://habr.com/ru/post/925043/


All Articles