浏览代码

SEC-1689: Minor doc updates related to use of password encoding and the crypto package.

Luke Taylor 14 年之前
父节点
当前提交
1dc309b041
共有 2 个文件被更改,包括 68 次插入57 次删除
  1. 66 55
      docs/manual/src/docbook/core-services.xml
  2. 2 2
      docs/manual/src/docbook/crypto.xml

+ 66 - 55
docs/manual/src/docbook/core-services.xml

@@ -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>

+ 2 - 2
docs/manual/src/docbook/crypto.xml

@@ -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");