A
HashedCredentialMatcher provides support for hashing of supplied
AuthenticationToken credentials
before being compared to those in the
AuthenticationInfo from the data store.
Credential hashing is one of the most common security techniques when safeguarding a user's private credentials
(passwords, keys, etc). Most developers never want to store their users' credentials in plain form, viewable by
anyone, so they often hash the users' credentials before they are saved in the data store.
This class (and its subclasses) function as follows:
- Hash the
AuthenticationToken credentials supplied by the user during their login.
- Compare this hashed value directly with the
AuthenticationInfo credentials stored in the system
(the stored account credentials are expected to already be in hashed form).
- If these two values are
#equals(Object,Object), the submitted credentials match, otherwise
they do not.
Salting and Multiple Hash Iterations
Because simple hashing is usually not good enough for secure applications, this class also supports 'salting'
and multiple hash iterations. Please read this excellent
Hashing Java article to learn about
salting and multiple iterations and why you might want to use them. (Note of sections 5
"Why add salt?" and 6 "Hardening against the attacker's attack"). We should also note here that all of
Shiro's Hash implementations (for example,
org.apache.shiro.crypto.hash.Md5Hash,
org.apache.shiro.crypto.hash.Sha1Hash, etc) support salting and multiple hash iterations via
overloaded constructors.
Real World Case Study
In April 2010, some public Atlassian Jira and Confluence
installations (Apache Software Foundation, Codehaus, etc) were the target of account attacks and user accounts
were compromised. The reason? Jira and Confluence at the time did not salt user passwords and attackers were
able to use dictionary attacks to compromise user accounts (Atlassian has since
fixed the problem of course).
The lesson?
ALWAYS, ALWAYS, ALWAYS SALT USER PASSWORDS!
Salting
Prior to Shiro 1.1, salts could be obtained based on the end-user submitted
AuthenticationToken via the now-deprecated
#getSalt(org.apache.shiro.authc.AuthenticationToken) method. This however
could constitute a security hole since ideally salts should never be obtained based on what a user can submit.
User-submitted salt mechanisms are
much more susceptible to dictionary attacks and
SHOULD NOT be
used in secure systems. Instead salts should ideally be a secure randomly-generated number that is generated when
the user account is created. The secure number should never be disseminated to the user and always kept private
by the application.
Shiro 1.1
As of Shiro 1.1, it is expected that any salt used to hash the submitted credentials will be obtained from the
stored account information (represented as an
AuthenticationInfo instance). This is much
more secure because the salt value remains private to the application (Shiro will never store this value).
To enable this,
Realms should return
SaltedAuthenticationInfo instances
during authentication.
HashedCredentialsMatcher implementations will then use the provided
org.apache.shiro.authc.SaltedAuthenticationInfo#getCredentialsSalt for hashing. To avoid
security risks,
it is highly recommended that any existing
Realm implementations that support hashed credentials are
updated to return
SaltedAuthenticationInfo instances as soon as possible.
Shiro 1.0 Backwards Compatibility
Because of the identified security risk,
Realm implementations that support credentials hashing should
be updated to return
SaltedAuthenticationInfo instances as
soon as possible.
If this is not possible for some reason, this class will retain 1.0 backwards-compatible behavior of obtaining
the salt via the now-deprecated
#getSalt(AuthenticationToken) method. This
method will only be invoked if a
Realm does not return
SaltedAuthenticationInfo instances and
#isHashSalted() is
true.
But please note that the
#isHashSalted() property and the
#getSalt(AuthenticationToken) methods will be removed before the Shiro 2.0
release.
Multiple Hash Iterations
If you hash your users' credentials multiple times before persisting to the data store, you will also need to
set this class's
#setHashIterations(int) property. See the
Hashing Java article's
"Hardening against the attacker's attack" section to learn more about why you might want to use
multiple hash iterations.
MD5 & SHA-1 Notice
MD5 and
SHA-1 algorithms are now known to be vulnerable to
compromise and/or collisions (read the linked pages for more). While most applications are ok with either of these
two, if your application mandates high security, use the SHA-256 (or higher) hashing algorithms and their
supporting
CredentialsMatcher implementations.