1. 개요

Spring Security 4에서는 메모리 내 인증을 사용하여 암호를 일반 텍스트로 저장할 수있었습니다.

버전 5의 암호 관리 프로세스를 대대적으로 개편하여 암호 인코딩 및 디코딩을위한보다 안전한 기본 메커니즘을 도입했습니다. 이는 Spring 애플리케이션이 일반 텍스트로 비밀번호를 저장하는 경우 Spring Security 5로 업그레이드하면 문제가 발생할 수 있음을 의미합니다.

이 짧은 사용방법(예제)에서는 이러한 잠재적 인 문제 중 하나를 설명하고 솔루션을 시연합니다.

2. Spring Security 4

간단한 인 메모리 인증 (Spring 4에 유효)을 제공하는 표준 Security 구성을 보여주는 것으로 시작합니다.

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

이 오류는 메모리 내 인증에 대해 구성된 암호 인코더가 없기 때문에 주어진 암호를 디코딩 할 수 없음을 나타 냅니다.

3. Spring Security 5

PasswordEncoderFactories 클래스 위임 PasswordEncoder정의하여이 오류를 수정할 수 있습니다 .

이 인코더를 사용하여 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를 사용할 수 있습니다 .

이를 위해, 우리가 제공하는 암호문 앞에 {noop} 식별자 를 사용하여 password () 메서드에 접두사를 붙입니다 .

@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 프로젝트 에서 소스 코드를 찾을 수 있습니다 .