«1. Обзор
В Spring Security 4 можно было хранить пароли в виде обычного текста, используя аутентификацию в памяти.
Серьезный пересмотр процесса управления паролями в версии 5 представил более безопасный механизм по умолчанию для кодирования и декодирования паролей. Это означает, что если ваше приложение Spring хранит пароли в виде простого текста, обновление до Spring Security 5 может вызвать проблемы.
В этом коротком уроке мы опишем одну из этих потенциальных проблем и продемонстрируем решение.
2. Spring Security 4
Мы начнем с демонстрации стандартной конфигурации безопасности, обеспечивающей простую аутентификацию в памяти (действительно для Spring 4):
@Configuration
public class InMemoryAuthWebSecurityConfigurer
extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication()
.withUser("spring")
.password("secret")
.roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/private/**")
.authenticated()
.antMatchers("/public/**")
.permitAll()
.and()
.httpBasic();
}
}
Эта конфигурация определяет аутентификацию для всех /private/ сопоставленные методы и публичный доступ ко всему в /public/.
Если мы используем ту же конфигурацию в Spring Security 5, мы получим следующую ошибку:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
Ошибка говорит нам о том, что данный пароль не может быть декодирован, поскольку для нашего in -аутентификация памяти.
3. Spring Security 5
Мы можем исправить эту ошибку, определив DelegatingPasswordEncoder с классом PasswordEncoderFactories.
Мы используем этот кодировщик для настройки нашего пользователя с помощью AuthenticationManagerBuilder:
@Configuration
public class InMemoryAuthWebSecurityConfigurer
extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("spring")
.password(encoder.encode("secret"))
.roles("USER");
}
}
Теперь, с этой конфигурацией, мы сохраняем наш пароль в памяти с помощью BCrypt в следующем формате:
{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS
Хотя мы можем определить собственный набор кодировщиков паролей, рекомендуется придерживаться кодировщиков по умолчанию, предоставленных в PasswordEncoderFactories.
3.2. NoOpPasswordEncoder
Если по какой-либо причине мы не хотим кодировать настроенный пароль, мы можем использовать NoOpPasswordEncoder.
Для этого мы просто добавляем перед фразой-паролем, которую мы предоставляем методу password(), идентификатор {noop}:
@Configuration
public class InMemoryNoOpAuthWebSecurityConfigurer
extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication()
.withUser("spring")
.password("{noop}secret")
.roles("USER");
}
}
Таким образом, Spring Security будет использовать NoOpPasswordEncoder под капотом при сравнении пароля предоставленный пользователем с тем, который мы настроили выше.
Обратите внимание, однако, что мы никогда не должны использовать этот подход в рабочем приложении! Как говорится в официальной документации, NoOpPasswordEncoder устарел, чтобы указать, что это устаревшая реализация, и ее использование считается небезопасным.
3.3. Миграция существующих паролей
Мы можем обновить существующие пароли до рекомендуемых стандартов Spring Security 5 следующим образом:
-
Обновление сохраненных паролей в виде простого текста с закодированным значением:
String encoded = new BCryptPasswordEncoder().encode(plainTextPassword);
-
Добавление префикса к хэшированным сохраненным паролям с их известным идентификатором кодировщика: ~ ~~
{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
-
Запрос пользователей на обновление своих паролей, когда механизм кодирования для сохраненных паролей неизвестен
4. Заключение
В этом кратком примере мы обновили действующую конфигурацию аутентификации Spring 4 в памяти до Spring 5, используя новый механизм хранения паролей.
Как всегда, вы можете найти исходный код в проекте GitHub.