Storing users' passwords in clear-text in a database is definitely not safe as hackers may have read access to all user accounts stored in the database. It's common then to hash passwords and only store these hashes in the database. When running the authentication process, the hash of the password provided by the user is compared to the hash stored in the database. If both matches, the access is granted.
This looks like a perfect solution but some algorithms such as MD5 and its successor, SHA-1, are no longer considered secure, because it is too easy to create hash collisions with them.
That is, it takes too little computational effort to come up with a different input that produces the same MD5 or SHA-1 hash, and using the new, same-hash value gives an attacker the same access as if he had the originally-hashed value. This applies as well to the other Message-Digest algorithms: MD2, MD4, MD6, HAVAL-128, HMAC-MD5, DSA (which uses SHA-1), RIPEMD, RIPEMD-128, RIPEMD-160, HMACRIPEMD160.
For this reason, when PasswordEncoder
is used to authenticate user in a Spring application, it should use a secure algorithm. The
following algorithms are considered not safe and should not be used:
org.springframework.security.authentication.encoding.ShaPasswordEncoder
(Spring Security 4.2.x) org.springframework.security.authentication.encoding.Md5PasswordEncoder
(Spring Security 4.2.x) org.springframework.security.crypto.password.LdapShaPasswordEncoder
(Spring Security 5.0.x) org.springframework.security.crypto.password.Md4PasswordEncoder
(Spring Security 5.0.x) org.springframework.security.crypto.password.MessageDigestPasswordEncoder
(Spring Security 5.0.x) org.springframework.security.crypto.password.NoOpPasswordEncoder
(Spring Security 5.0.x) org.springframework.security.crypto.password.StandardPasswordEncoder
(Spring Security 5.0.x) org.springframework.security.crypto.scrypt.SCryptPasswordEncoder
(Spring Security 5.0.x) Consider using safer alternatives, such as org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
(preferred) or
org.springframework.security.crypto.password.Pbkdf2PasswordEncoder
.
@Autowired public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception { auth.jdbcAuthentication() .dataSource(dataSource) .usersByUsernameQuery("SELECT * FROM users WHERE username = ?") .passwordEncoder(new StandardPasswordEncoder()); // Noncompliant // OR auth.jdbcAuthentication() .dataSource(dataSource) .usersByUsernameQuery("SELECT * FROM users WHERE username = ?"); // Noncompliant; default uses plain-text // OR auth.userDetailsService(...); // Noncompliant; default uses plain-text // OR auth.userDetailsService(...).passwordEncoder(new StandardPasswordEncoder()); // Noncompliant }
@Autowired public void configureGlobal(AuthenticationManagerBuilder auth, DataSource dataSource) throws Exception { auth.jdbcAuthentication() .dataSource(dataSource) .usersByUsernameQuery("Select * from users where username=?") .passwordEncoder(new BCryptPasswordEncoder()); // or auth.userDetailsService(null).passwordEncoder(new BCryptPasswordEncoder()); }