6.4. Password Hashing¶
Caution
This version is already obsolete. Please check the latest guideline.
Table of contents
6.4.1. Overview¶
org.springframework.security.crypto.password.PasswordEncoder interface, as the password hashing mechanism.org.springframework.security.crypto.bcrypt.BCryptPasswordEncoderorg.springframework.security.crypto.password.StandardPasswordEncoder
PasswordEncoder mechanism, password is hashed by encode(String rawPassword) method and the encoded password is verified bymatches (String rawPassword, String encodedPassword) method.6.4.2. How to use¶
List of PasswordEncoder implementation classes
| PasswordEncoder implementation classes | Overview |
|---|---|
org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder |
Encoder that performs hashing using “bcrypt” algorithm
|
org.springframework.security.crypto.password.StandardPasswordEncoder |
Encoder that performs hashing with “SHA-256” algorithm + 1024 rounds of stretching
|
org.springframework.security.crypto.password.NoOpPasswordEncoder |
Encoder that does not perform hashing (for testing)
|
It is recommended to use BCryptPasswordEncoder when hashing is not required.
However, the calculation time taken by BCryptPasswordEncoder to improve counter-attacks being more,
if the performance requirements at the time of authentication are not fulfilled, StandardPasswordEncoder should be considered.
In case of any restrictions concerning salt and hashed algorithm owing to the relation with existing system,
implementation class of org.springframework.security.authentication.encoding.PasswordEncoder interface, which will be described later, should be used.
For details, refer How to extend.
6.4.2.1. BCryptPasswordEncoder¶
BCryptPasswordEncoder is the class that implements PasswordEncoder and provides password hashing.Note
In Bcrypt algorithm, number of calculations have been intentionally increased to more than the calculations of the standard algorithms. Therefore, compared to standard algorithms (SHA, MD5), it has strong features to resist “offline brute force attack”.
6.4.2.1.1. Configuration example of BCryptPasswordEncoder¶
applicationContext.xml
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> <!-- (1) -->
Sr. No. Description (1)SpecifyBCryptPasswordEncoderin passwordEncoder class.Number of salt hash rounds can be specified as constructor argument. Values from 4 to 31 can be set.Longer the salt value, stronger the hashing. However, as number of calculations increase exponentially, it is necessary to exercise caution from performance perspective.When no value is specified, “10” is set.Tip
It is described later in ‘How to extend’; however, DaoAuthenticationProvider can set the implementation class of
org.springframework.security.crypto.password.PasswordEncoderas well as the implementation class oforg.springframework.security.authentication.encoding.PasswordEncoder. Therefore, when the existing PasswordEncoder (authentication package) is changed to a new PasswordEncoder, it can be handled only by changing the passwordEncoder of DaoAuthenticationProvider, after changing the user password.Warning
When
DaoAuthenticationProvideris set in authentication provider andUsernameNotFoundExceptionis thrown, without letting the person operating the system know that user does not exist, password is intentionally hashed afterUsernameNotFoundExceptionis thrown. (Side channel attack countermeasure)To create values for this hashing,
encodemethod is once executed internally when starting the application.Warning
When SecureRandom is used in Linux environment, the process may be delayed or timeout may occur. The cause of this issue is random number generation and is described in the following Java Bug Database.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6202721
It has been corrected in the JDK 7 version b20 and above.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6521844
This issue can be avoided by setting the following as JVM boot arguments.
-Djava.security.egd=file:///dev/urandom
Java class
@Inject PasswordEncoder passwordEncoder; // (1) public String register(Customer customer, String rawPassword) { // omitted // Password Hashing String password = passwordEncoder.encode(rawPassword); // (2) customer.setPassword(password); // omitted } public boolean matches(Customer customer, String rawPassword) { return passwordEncoder.matches(rawPassword, customer.getPassword()); // (3) }
Sr. No. Description (1)InjectPasswordEncoderfor which bean definition is carried out.(2)Password hashing exampleBy specifying the plaintext password as an argument of encode method, hashed password is returned.(3)Password verification exampleBy specifying plaintext password as the first argument and hashed password as the second argument,‘matches’ method checks whether both the passwords match.
6.4.2.2. StandardPasswordEncoder¶
StandardPasswordEncoder uses SHA-256 as the hashing algorithm and performs 1024 rounds of stretching.encode(String rawPassword) method and matches(String rawPassword, String encodedPassword) methodStandardPasswordEncoder are described below.encode(String rawPassword) method
matches(String rawPassword, String encodedPassword) method
6.4.2.2.1. Configuration example of StandardPasswordEncoder¶
applicationContext.xml
<bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"> <!-- from properties file --> <constructor-arg value="${passoword.encoder.secret}"/> <!-- (1) --> </bean>
Sr. No. Description (1)Specify the secret key for hashing.When specified, password is hashed with “internally generated salt” + “specified secret key” + “password”.It is recommended to specify secret key, as the strength against rainbow table attack reduces if not specified.About secret keySecret key should be handled as confidential information.Therefore, instead of specifying it directly in the Spring Security configuration file, fetch it from properties file or environment variable etc.Here, example of fetching the secret key from properties file is enabled. Further, care should be taken regarding the storage location of properties file in a production environment.Tip
When secret key is fetched from environment variables
It can be fetched by performing the following settings in
<constructor-arg>of StandardPasswordEncoder bean definition.<bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"> <!-- from environment variable --> <constructor-arg value="#{systemEnvironment['PASSWORD_ENCODER_SECRET']}" /> <!-- (1) --> </bean>
Sr. No. Description (1)Fetch value from environment variable PASSWORD_ENCODER_SECRET.Refer to Configuration example of BCryptPasswordEncoder, as example of Java class is the same asBCryptPasswordEncoder.
6.4.2.3. NoOpPasswordEncoder¶
NoOpPasswordEncoder is the encoder that returns the specified value as a string without any change.6.4.3. How to extend¶
PasswordEncoder mentioned above.PasswordEncoder mentioned above, does not fulfill the requirements.- For example we may consider a case wherein the existing hashing system is as follows:
- Algorithm used is SHA-512.
- There are 1000 rounds of stretching.
- Salt is stored in account table column and needs to be passed externally from
PasswordEncoder.
org.springframework.security.authentication.encoding.PasswordEncoder of a different packageorg.springframework.security.crypto.password.PasswordEncoder.Warning
In versions prior to Spring Security 3.1.4, the class that implements
org.springframework.security.authentication.encoding.PasswordEncoderwas used for hashing. However, it has been deprecated from Spring Security version 3.1.4 onwards. Therefore, it differs from the pattern recommended by Spring.
6.4.3.1. Example where ShaPasswordEncoder is used¶
applicationContext.xml
<bean id ="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"> <!-- (1) --> <constructor-arg value="512" /> <!-- (2) --> <property name="iterations" value="1000" /> <!-- (3) --> </bean>
Sr. No. Description (1)Specifyorg.springframework.security.authentication.encoding.ShaPasswordEncoderas the passwordEncoder.The class to be specified in passwordEncoder should change according to the algorithm to be used.(2)Set the SHA algorithm type as constructor argument.The values “1, 256, 384, 512” can be set. When omitted, “1” is set.(4)Specify the number of stretching rounds at the time of hashing.When omitted, it is 0.spring-mvc.xml
<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <!-- omitted --> <property name="saltSource" ref="saltSource" /> <!-- (1) --> <property name="userDetailsService" ref="userDetailsService" /> <property name="passwordEncoder" ref="passwordEncoder" /> <!-- (2) --> </bean> <bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource"> <!-- (3) --> <property name="userPropertyToUse" value="username" /> <!-- (4) --> </bean>
Sr. No. Description (1)When salt is to be defined externally, set BeanId of the class that implementsorg.springframework.security.authentication.dao.SaltSource.In this example,org.springframework.security.authentication.dao.ReflectionSaltSourcethat fetches the value set in user information class by reflection, is defined.(2)Specifyorg.springframework.security.authentication.encoding.ShaPasswordEncoderas the passwordEncoder.The class to be specified in passwordEncoder should change according to the algorithm to be used.(3)Specifyorg.springframework.security.authentication.dao.SaltSourcethat decides how to create salt.Here,ReflectionSaltSourceresource that fetchesUserDetailsobject property by reflection, is used.(4)usernameproperty ofUserDetailsobject is used as salt.Java class
@Inject PasswordEncoder passwordEncoder; public String register(Customer customer, String rawPassword, String userSalt) { // omitted String password = passwordEncoder.encodePassword(rawPassword, userSalt); // (1) customer.setPassword(password); // omitted } public boolean matches(Customer customer, String rawPassword, String userSalt) { return passwordEncoder.isPasswordValid(customer.getPassword(), rawPassword, userSalt); // (2) }
Sr. No. Description (1)To hash password,specify password and salt string as the argument ofencodePasswordmethodof the class that implementsorg.springframework.security.authentication.encoding.PasswordEncoder.(2)To verify password,UsingisPasswordValidmethod, hashed password, plain text password andsalt string are specified as the argument and the hashed password and plaintext passwords are compared.
6.4.4. Appendix¶
Note
About stretch
By repeating the hash function computation, information regarding password to be stored can be repeatedly encoded. This is done to prolong the time required to crack a password, and thus acts as a countermeasure against the brute force attack. However, since stretching affects system performance, it is necessary to decide the stretch count on considering the system performance.
Note
About salt
Salt is the string assigned to the original data to be encoded. By assigning salt to a password, the length of the password is increased and thus makes it difficult to crack passwords using rainbow attacks etc. Further, if the same salt is used for multiple users and if there are users who have the same password, it will be obvious from the hash value that same password is used. Therefore, it is recommended to use a different salt (random value etc.) for each user.


