SEC-1689: Minor doc updates related to use of password encoding and the crypto package.
This commit is contained in:
parent
e470eaa41d
commit
1dc309b041
|
@ -73,24 +73,23 @@
|
|||
authenticate is made.</para>
|
||||
<section xml:id="core-services-erasing-credentials">
|
||||
<title>Erasing Credentials on Successful Authentication</title>
|
||||
<para>
|
||||
By default (from Spring Security 3.1 onwards) the <classname>ProviderManager</classname>
|
||||
will attempt to clear any sensitive credentials information from the
|
||||
<interfacename>Authentication</interfacename> object which is returned by a successful
|
||||
authentication request. This prevents information like passwords being retained longer
|
||||
than necessary.
|
||||
</para>
|
||||
<para>
|
||||
This may cause issues when you are using a cache of user objects, for example, to
|
||||
improve performance in a stateless application. If the <interfacename>Authentication</interfacename>
|
||||
contains a reference to an object in the cache (such as a <interfacename>UserDetails</interfacename>
|
||||
instance) and this has its credentials removed, then it will no longer be possible to authenticate
|
||||
against the cached value. You need to take this into account if you are using a cache. An obvious
|
||||
solution is to make a copy of the object first, either in the cache implementation or in
|
||||
the <interfacename>AuthenticationProvider</interfacename> which creates the returned
|
||||
<interfacename>Authentication</interfacename> object. Alternatively, you can disable the
|
||||
<literal>eraseCredentialsAfterAuthentication</literal> property on <classname>ProviderManager</classname>.
|
||||
See the Javadoc for more information.
|
||||
<para> By default (from Spring Security 3.1 onwards) the
|
||||
<classname>ProviderManager</classname> will attempt to clear any sensitive
|
||||
credentials information from the <interfacename>Authentication</interfacename>
|
||||
object which is returned by a successful authentication request. This prevents
|
||||
information like passwords being retained longer than necessary. </para>
|
||||
<para> This may cause issues when you are using a cache of user objects, for example, to
|
||||
improve performance in a stateless application. If the
|
||||
<interfacename>Authentication</interfacename> contains a reference to an object in
|
||||
the cache (such as a <interfacename>UserDetails</interfacename> instance) and this
|
||||
has its credentials removed, then it will no longer be possible to authenticate
|
||||
against the cached value. You need to take this into account if you are using a
|
||||
cache. An obvious solution is to make a copy of the object first, either in the
|
||||
cache implementation or in the <interfacename>AuthenticationProvider</interfacename>
|
||||
which creates the returned <interfacename>Authentication</interfacename> object.
|
||||
Alternatively, you can disable the
|
||||
<literal>eraseCredentialsAfterAuthentication</literal> property on
|
||||
<classname>ProviderManager</classname>. See the Javadoc for more information.
|
||||
</para>
|
||||
</section>
|
||||
<section xml:id="core-services-dao-provider">
|
||||
|
@ -107,17 +106,13 @@
|
|||
<bean id="daoAuthenticationProvider"
|
||||
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
|
||||
<property name="saltSource" ref="saltSource"/>
|
||||
<property name="passwordEncoder" ref="passwordEncoder"/>
|
||||
</bean>]]></programlisting> The <interfacename>PasswordEncoder</interfacename> and
|
||||
<interfacename>SaltSource</interfacename> are optional. A
|
||||
</bean>]]></programlisting> The <interfacename>PasswordEncoder</interfacename> is optional. A
|
||||
<interfacename>PasswordEncoder</interfacename> provides encoding and decoding of
|
||||
passwords presented in the <interfacename>UserDetails</interfacename> object that is
|
||||
returned from the configured <interfacename>UserDetailsService</interfacename>. A
|
||||
<interfacename>SaltSource</interfacename> enables the passwords to be populated with
|
||||
a "salt", which enhances the security of the passwords in the authentication
|
||||
repository. These will be discussed in more detail <link
|
||||
xlink:href="#core-services-password-encoding">below</link>. </para>
|
||||
returned from the configured <interfacename>UserDetailsService</interfacename>. This
|
||||
will be discussed in more detail <link xlink:href="#core-services-password-encoding"
|
||||
>below</link>. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -129,7 +124,8 @@
|
|||
<para>
|
||||
<programlisting language="java">
|
||||
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
|
||||
</programlisting> </para>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>The returned <interfacename>UserDetails</interfacename> is an interface that provides
|
||||
getters that guarantee non-null provision of authentication information such as the
|
||||
username, password, granted authorities and whether the user account is enabled or
|
||||
|
@ -179,7 +175,8 @@
|
|||
<interfacename>UserDetailsService</interfacename> to reuse the mapping files you've
|
||||
probably already created. Returning to <literal>JdbcDaoImpl</literal>, an example
|
||||
configuration is shown below:</para>
|
||||
<para> <programlisting language="xml"><![CDATA[
|
||||
<para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
|
||||
|
@ -190,7 +187,8 @@
|
|||
<bean id="userDetailsService"
|
||||
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean> ]]> </programlisting> </para>
|
||||
</bean> ]]> </programlisting>
|
||||
</para>
|
||||
<para>You can use different relational database management systems by modifying the
|
||||
<literal>DriverManagerDataSource</literal> shown above. You can also use a global
|
||||
data source obtained from JNDI, as with any other Spring configuration.</para>
|
||||
|
@ -219,10 +217,18 @@
|
|||
</section>
|
||||
<section xml:id="core-services-password-encoding">
|
||||
<title>Password Encoding</title>
|
||||
<para>Spring Security's <interfacename>PasswordEncoder</interfacename> interface is used to
|
||||
support the use of passwords which are encoded in some way in persistent storage. This
|
||||
will normally mean that the passwords are <quote>hashed</quote> using a digest algorithm
|
||||
such as MD5 or SHA.</para>
|
||||
<para xlink:href="#spring-security-crypto-passwordencoders">Spring Security's
|
||||
<interfacename>PasswordEncoder</interfacename> interface is used to support the use of
|
||||
passwords which are encoded in some way in persistent storage. This will normally mean
|
||||
that the passwords are <quote>hashed</quote> using a digest algorithm such as MD5 or
|
||||
SHA. Spring Security 3.1's <link xlink:href="#spring-security-crypto-passwordencoders"
|
||||
><literal>crypto</literal></link> package introduces a simpler API which encourages
|
||||
best-practice for password hashing. We would encourage you to use these APIs for new
|
||||
development and regard the classes in package
|
||||
<literal>org.springframework.security.authentication.encoding</literal> as legacy
|
||||
implementations. The <classname>DaoAuthenticationProvider</classname> can be injected
|
||||
with either the new or legacy <interfacename>PasswordEncoder</interfacename>
|
||||
types.</para>
|
||||
<section>
|
||||
<title>What is a hash?</title>
|
||||
<para>Password hashing is not unique to Spring Security but is a common source of
|
||||
|
@ -232,8 +238,8 @@
|
|||
the string <quote>password</quote> (in hexadecimal) is
|
||||
<programlisting language="txt">
|
||||
5f4dcc3b5aa765d61d8327deb882cf99
|
||||
</programlisting> A hash is
|
||||
<quote>one-way</quote> in the sense that it is very difficult (effectively
|
||||
</programlisting>
|
||||
A hash is <quote>one-way</quote> in the sense that it is very difficult (effectively
|
||||
impossible) to obtain the original input given the hash value, or indeed any
|
||||
possible input which would produce that hash value. This property makes hash values
|
||||
very useful for authentication purposes. They can be stored in your user database as
|
||||
|
@ -254,16 +260,28 @@
|
|||
<quote>salt</quote> when calculating the hashes. This is an additional string of
|
||||
known data for each user which is combined with the password before calculating the
|
||||
hash. Ideally the data should be as random as possible, but in practice any salt
|
||||
value is usually preferable to none. Spring Security has a
|
||||
<interfacename>SaltSource</interfacename> interface which can be used by an
|
||||
authentication provider to generate a salt value for a particular user. Using a salt
|
||||
means that an attacker has to build a separate dictionary of hashes for each salt
|
||||
value, making the attack more complicated (but not impossible).</para>
|
||||
value is usually preferable to none. Using a salt means that an attacker has to
|
||||
build a separate dictionary of hashes for each salt value, making the attack more
|
||||
complicated (but not impossible).</para>
|
||||
<para>The <classname>StandardPasswordEncoder</classname> in the <link
|
||||
xlink:href="#spring-security-crypto-passwordencoders"
|
||||
><literal>crypto</literal></link> package uses a random 8-byte salt, which is stored
|
||||
in the same field as the password.<note>
|
||||
<para>The legacy approach to handling salt was to inject a
|
||||
<interfacename>SaltSource</interfacename> into the
|
||||
<classname>DaoAuthenticationProvider</classname>, which would obtain a salt
|
||||
value for a particular user and pass it to the
|
||||
<interfacename>PasswordEncoder</interfacename>. Using a random salt and
|
||||
combining it with the password data field means you don't have to worry about
|
||||
the details of salt handling (such as where the the value is stored), as it is
|
||||
all done internally. So we'd strongly recommend you use this approach unless you
|
||||
already have a system in place which stores the salt separately.</para>
|
||||
</note></para>
|
||||
</section>
|
||||
<section>
|
||||
<title> Hashing and Authentication</title>
|
||||
<para>When an authentication provider (such as Spring Security's
|
||||
<classname>DaoAuthenticationProvider</classname> needs to check the password in a
|
||||
<classname>DaoAuthenticationProvider</classname>) needs to check the password in a
|
||||
submitted authentication request against the known value for a user, and the stored
|
||||
password is encoded in some way, then the submitted value must be encoded using
|
||||
exactly the same algorithm. It's up to you to check that these are compatible as
|
||||
|
@ -274,20 +292,13 @@
|
|||
example, and your application is configured to use Spring Security's
|
||||
<classname>Md5PasswordEncoder</classname>, there are still things that can go wrong.
|
||||
The database may have the passwords encoded in Base 64, for example while the
|
||||
enocoder is using hexadecimal strings (the default)<footnote>
|
||||
<para>You can configure the encoder to use Base 64 instead of hex by setting the
|
||||
<literal>encodeHashAsBase64</literal> property to <literal>true</literal>. Check
|
||||
the Javadoc for <classname>MessageDigestPasswordEncoder</classname> and its
|
||||
parent classes for more information.</para>
|
||||
</footnote>. Alternatively your database may be using upper-case while the output
|
||||
from the encoder is lower-case. Make sure you write a test to check the output from
|
||||
your configured password encoder with a known password and salt combination and
|
||||
check that it matches the database value before going further and attempting to
|
||||
authenticate through your application. For more information on the default method
|
||||
for merging salt and password, see the Javadoc for
|
||||
<classname>BasePasswordEncoder</classname>. If you want to generate encoded
|
||||
passwords directly in Java for storage in your user database, then you can use the
|
||||
<methodname>encodePassword</methodname> method on the
|
||||
encoder is using hexadecimal strings (the default). Alternatively your database may
|
||||
be using upper-case while the output from the encoder is lower-case. Make sure you
|
||||
write a test to check the output from your configured password encoder with a known
|
||||
password and salt combination and check that it matches the database value before
|
||||
going further and attempting to authenticate through your application.</para>
|
||||
<para>If you want to generate encoded passwords directly in Java for storage in your
|
||||
user database, then you can use the <methodname>encode</methodname> method on the
|
||||
<interfacename>PasswordEncoder</interfacename>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
@ -109,7 +109,7 @@ KeyGenerators.string();]]>
|
|||
<title>Password Encoding</title>
|
||||
<para>
|
||||
The password package of the spring-security-crypto module provides support for encoding passwords.
|
||||
PasswordEncoder is the central service interface and has the following signature:
|
||||
<interfacename>PasswordEncoder</interfacename> is the central service interface and has the following signature:
|
||||
<programlisting language="java"><![CDATA[
|
||||
public interface PasswordEncoder {
|
||||
String encode(String rawPassword);
|
||||
|
@ -120,7 +120,7 @@ public interface PasswordEncoder {
|
|||
This method is designed to support password-based authentication schemes.
|
||||
</para>
|
||||
<para>
|
||||
The StandardPasswordEncoder implementation applies 1024 iterations of the SHA-256 hashing algorithm to the rawPassword combined with a site-wide secret and 8-byte random salt:
|
||||
The <classname>StandardPasswordEncoder</classname> implementation applies 1024 iterations of the SHA-256 hashing algorithm to the rawPassword combined with a site-wide secret and 8-byte random salt:
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[
|
||||
StandardPasswordEncoder encoder = new StandardPasswordEncoder("secret");
|
||||
|
|
Loading…
Reference in New Issue