You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Mike K <mk...@semanticresearch.com> on 2010/09/02 08:31:02 UTC

Password Salting (one salt per password)

I am looking to use per-password salting using random numbers.
Looking at the HashedCredentialsMatcher.getSalt it uses the
AuthenticationToken  (the user name) for salt. 
Any recommendations on how to extend the getSalt api in order to retrieve a
salt stored with a DAO? It seems like the Realm would be the right place for
this, but the current API does not seem to support something like that. 
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5490030.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Thanks that makes a lot of sense. Specifically, I was concerned about data
access, making more data retrieval calls. But the suggestion of keeping the
salt with the password solves that problem.
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5491825.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Kalle Korhonen <ka...@gmail.com>.
(Being a committer, it may sound a bit odd I say this but...) yeah,
I've wondered about this too. As you mentioned, out of the box, the
API supports deriving salt from an AuthenticationToken (you can argue
about the effectiveness). As stated in
http://incubator.apache.org/shiro/static/current/apidocs/org/apache/shiro/authc/credential/HashedCredentialsMatcher.html#getSalt(org.apache.shiro.authc.AuthenticationToken):
"This default implementation merely returns token.getPrincipal(),
effectively using the user's identity (username, user id, etc) as the
salt, a most common technique. If you wish to provide the
authentication token's salt another way, you may override this method.
"

Most common or not but if you bother to salt the password why not do
it properly. For Xnix-style, fixed-width, per-password random salt,
you need to implement your own CredentialsMatcher and an additional
encode() operation somewhere (I keep mine with my custom
CredentialsMatcher out of convenience), something like this (for a
fixed-width salt):
public static String encode(String password, int saltWidth, int
hashIterations) {...}
that knows how to encode and prefix the salt to the encoded password.
Obviously, you also need something like:
protected String getSalt(AuthenticationInfo token) {...}
whereas the default operation simply does:
	@Override
	protected Object getSalt(AuthenticationToken token) {
		return new NoSuchAlgorithmException("Cannot return salt without
authentication info");
	}

After that, you simply to need to set the CredentialsMatcher to your
realm. The current CredentialsMatcher implementation is a bit
trigger-happy with inheritance... to me, a single CredentialsMatcher
with specific algorithm set as a property should have been enough to
cover the use cases for the existing classes and inheritance should be
reserved for denoting logically different behavior of the
CredentialsMatchers. Not that it would be too late to change that.
Feel free to open an issue (and add a patch!).

Kalle



On Wed, Sep 1, 2010 at 11:31 PM, Mike K <mk...@semanticresearch.com> wrote:
>
> I am looking to use per-password salting using random numbers.
> Looking at the HashedCredentialsMatcher.getSalt it uses the
> AuthenticationToken  (the user name) for salt.
> Any recommendations on how to extend the getSalt api in order to retrieve a
> salt stored with a DAO? It seems like the Realm would be the right place for
> this, but the current API does not seem to support something like that.
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5490030.html
> Sent from the Shiro User mailing list archive at Nabble.com.
>

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Joined. 
Thank you.
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5651918.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Les Hazlewood <lh...@apache.org>.
Hi Mike,

I should have something in for that today.  Please join the dev list
as I'll probably raise some discussion about it for peer review.

Cheers,

Les

On Sun, Oct 17, 2010 at 3:58 PM, Mike K <mk...@semanticresearch.com> wrote:
>
> Any chance of that snapshot being available?
> Sorry, I have lost track and have not seen changes on jira.
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5645421.html
> Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Any chance of that snapshot being available?
Sorry, I have lost track and have not seen changes on jira.
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5645421.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Les Hazlewood <lh...@apache.org>.
Yep, it is.  It will of course be in the 1.1-SNAPSHOT before then, but
because it is a new feature with an added interface, we can't do it as
a point release (1.0.x), since point releases should be 100% forwards
and backwards compatible.

Where possible, we try to adhere to these version guidelines:
http://apr.apache.org/versioning.html

HTH,

-- 
Les Hazlewood
Founder, Katasoft, Inc.
Application Security Products & Professional Apache Shiro Support and Training:
http://www.katasoft.com

On Mon, Oct 11, 2010 at 10:25 AM, Mike K <mk...@semanticresearch.com> wrote:
>
> Les, is this planned for 1.1?
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5623927.html
> Sent from the Shiro User mailing list archive at Nabble.com.
>

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Les, is this planned for 1.1?
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5623927.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Les Hazlewood <lh...@apache.org>.
Thanks Kalle.

-- 
Les Hazlewood
Founder, Katasoft, Inc.
Application Security Products & Professional Apache Shiro Support and Training:
http://www.katasoft.com

On Mon, Oct 4, 2010 at 11:55 AM, Kalle Korhonen
<ka...@gmail.com> wrote:
> Since 186 is already assigned I linked & marked 176 as duplicate of 186.
>
> Kalle
>
>
> On Mon, Oct 4, 2010 at 11:12 AM, Mike K <mk...@semanticresearch.com> wrote:
>>
>> Les, I am watching the following Jiras:
>> https://issues.apache.org/jira/browse/SHIRO-176
>> https://issues.apache.org/jira/browse/SHIRO-186
>> which seem to be duplicates.
>>
>> Cheers,
>>
>> Mike.
>> --
>> View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5600246.html
>> Sent from the Shiro User mailing list archive at Nabble.com.
>>
>

Re: Password Salting (one salt per password)

Posted by Kalle Korhonen <ka...@gmail.com>.
Since 186 is already assigned I linked & marked 176 as duplicate of 186.

Kalle


On Mon, Oct 4, 2010 at 11:12 AM, Mike K <mk...@semanticresearch.com> wrote:
>
> Les, I am watching the following Jiras:
> https://issues.apache.org/jira/browse/SHIRO-176
> https://issues.apache.org/jira/browse/SHIRO-186
> which seem to be duplicates.
>
> Cheers,
>
> Mike.
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5600246.html
> Sent from the Shiro User mailing list archive at Nabble.com.
>

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Les, I am watching the following Jiras:
https://issues.apache.org/jira/browse/SHIRO-176
https://issues.apache.org/jira/browse/SHIRO-186
which seem to be duplicates.

Cheers,

Mike.
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5600246.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Les Hazlewood <lh...@apache.org>.
Hi Mike,

Not yet, but I'll probably be able to get to it this weekend.

Cheers,

-- 
Les Hazlewood
Founder, Katasoft, Inc.
Application Security Products & Professional Apache Shiro Support and Training:
http://www.katasoft.com

> per-password salting you mentioned?
>
> Regards,
>
> Mike.
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5585647.html
> Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Les, just checking in to see if you had a chance to check in the stronger
per-password salting you mentioned?

Regards, 

Mike.
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5585647.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Thanks Les. I might cook something up before that as necessary.
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5507302.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Les Hazlewood <lh...@apache.org>.
I have a big work deadline next week, so I probably won't be able to
work on it until the week after that.  Any work done would go into
trunk and then be available in the 1.1 release.  1.1 should be
released very shortly after we become a Top Level Project this month.
So, I'd give it a few weeks.  Dunno if that complicates things for
you, but there you are :)

Best,

Les

On Fri, Sep 3, 2010 at 2:25 PM, Mike K <mk...@semanticresearch.com> wrote:
>
> Les this sounds exactly what I was looking for. I was just about to start
> work on this, but if it is going to be available in Shiro, I might choose to
> tackle something else. When do you think this might be available?
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5497034.html
> Sent from the Shiro User mailing list archive at Nabble.com.
>

Re: Password Salting (one salt per password)

Posted by Mike K <mk...@semanticresearch.com>.
Les this sounds exactly what I was looking for. I was just about to start
work on this, but if it is going to be available in Shiro, I might choose to
tackle something else. When do you think this might be available?
-- 
View this message in context: http://shiro-user.582556.n2.nabble.com/Password-Salting-one-salt-per-password-tp5490030p5497034.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Password Salting (one salt per password)

Posted by Les Hazlewood <lh...@apache.org>.
P.S.  I want to also contribute the random-number generation logic
back to the project as well, I'm just not sure where to put it yet
(gotta figure this out on the dev list).

Here is how I do it at the moment:  I have a UserService with the
following (simplified for clarity) create(User) method:

public long create(User user) {
    if (user == null) {
        throw new NullPointerException("User instance cannot be null.");
    } else if (userDao.findByUsername(user.getUsername()) != null) {
        throw new ExistingUserException("A user with username " +
user.getUsername() + " already exists");
    }

    DateTime now = new DateTime();
    user.setCreated(now);
    user.setUpdated(now);

    //the password saved to the database is actually a password hash -
not the plain text sent from the UI
    //so, convert the plain text one to a hashed one:
    ByteSource generatedSalt = generatePasswordSalt();
    String base64PasswordSalt = generatedSalt.toBase64();
    user.setPassword(new Sha512Hash(user.getPassword(),
generatedSalt.getBytes(),
            PASSWORD_NUM_ITERATIONS).toBase64());
    //store the password salt along side the password
    user.setPasswordSalt(base64PasswordSalt);

    return (Long) userDao.create(user);
}

As you can see, I store the salt in its Base64-encoded string form.
You could also save it as the raw byte array (blob).

This method calls the generatePasswordSalt() method:

private ByteSource generatePasswordSalt() {
    byte[] saltBytes = new byte[PASSWORD_SALT_NUM_BYTES];
    try {
        SecureRandom.getInstance(RANDOM_NUM_GENERATOR_ALGORITHM_NAME).nextBytes(saltBytes);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
    return new SimpleByteSource(saltBytes);
}

Where in my case, PASSWORD_SALT_NUM_BYTES = 128 and
RANDOM_NUM_GENERATOR_ALGORITHM_NAME = "SHA1PRNG"

My Realm implementation returns the SaltedAuthenticationInfo instance
where the getSalt() method returns the value of
Base64.decode(user.getPasswordSalt()) - to convert the base-64 encoded
stored string back into the original bytes so they can be used
directly by the CredentialsMatcher.  If you stored the byte array/blob
directly, you wouldn't need to perform this step.

This salting technique is the most secure that I know of since it
doesn't rely on any user attribute - i.e. it is totally random and not
guessable by an attacker.  IMO, it should definitely find its way into
Shiro so our end-users don't need to repeat this logic themselves.  To
be discussed on the dev list...

Cheers,

Les

Re: Password Salting (one salt per password)

Posted by Les Hazlewood <lh...@apache.org>.
Yes, as you've noticed, and as Kalle mentioned, this was an oversight
in the API back in the pre 1.0 days - it is not safe to obtain a salt
based on what the end-user submits (i.e. what is represented by an
AuthenticationToken).  System that obtain salts this way susceptible
to inference attacks.  Instead, it is *much* safer to obtain the salt
from the stored account data (what is represented by an
AuthenticationInfo instance). And even then, a salt should be ideally
created from a cryptographically-strong random number generator, and
not by using account data (password, username, whatever).

Here is how I've solved it in my applications, and I hope to get some
time to contribute this back to the project - it is a much cleaner
solution, and very similar to Kalle's.

First, because we want the salt to come from the stored account data
it makes much more sense for the salt to be represented in the
AuthenticationInfo returned from the Realm.  So, I created an
AuthenticationInfo sub-interface:

/**
 * An AuthenticationInfo instance that represents a salt used to hash
the stored credentials.
 */
public interface SaltedAuthenticationInfo extends AuthenticationInfo {

    /**
     * Returns the salt used to hash the credentials.
     *
     * @return the salt used to hash the credentials.
     */
    Object getSalt();
}

An instance of this interface is returned from my Realm's
doGetAuthenticationInfo implementation.  Bringing this in to Shiro's
API should work fine (or it can be a standalone interface,
'SaltSource' or something like that, but since Shiro has no need to
reference a salt outside of the AuthenticationInfo context, I thought
a sub-interface would be fine).

Next, I created a subclass of the HashedCredentialsMatcher I'm using.
In this case, I'm using the Sha512CredentialsMatcher:

public class SaltedSha512CredentialsMatcher extends Sha512CredentialsMatcher {

    /**
     * This implementation acquires the <tt>token</tt>'s credentials
     * (via {@link #getCredentials(AuthenticationToken) getCredentials(token)})
     * and then the <tt>account</tt>'s credentials
     * (via {@link
#getCredentials(org.apache.shiro.authc.AuthenticationInfo)
getCredentials(account)}) and then passes both of
     * them to the {@link #equals(Object,Object)
equals(tokenCredentials, accountCredentials)} method for equality
     * comparison.
     *
     * @param token the <tt>AuthenticationToken</tt> submitted during
the authentication attempt.
     * @param info  the <tt>AuthenticationInfo</tt> stored in the
system matching the token principal.
     * @return <tt>true</tt> if the provided token credentials are
equal to the stored account credentials,
     *         <tt>false</tt> otherwise
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token,
AuthenticationInfo info) {
        Object tokenCredentials;
        if (isHashSalted()) {
            tokenCredentials = hashProvidedCredentials(token, info);
        } else {
            tokenCredentials = getCredentials(token);
        }
        Object accountCredentials = getCredentials(info);
        return equals(tokenCredentials, accountCredentials);
    }

    private Object hashProvidedCredentials(AuthenticationToken token,
AuthenticationInfo info) {
        Object salt;
        if (info instanceof SaltedAuthenticationInfo) {
            salt = ((SaltedAuthenticationInfo) info).getSalt();
        } else {
            //for backwards compatibility:
            salt = getSalt(token);
        }
        return hashProvidedCredentials(token.getCredentials(), salt,
getHashIterations());
    }
}

This logic should make its way into the base HashedCredentialsMatcher
implementation.

Finally, an instance of this CredentialsMatcher is configured on my Realm.

I'll try to contribute this to the codebase sometime this coming week,
after some brief discussion on the dev list.

I hope this helps!

Cheers,

Les