Spring Security PasswordEncoder

이상민·2021년 11월 12일
0

스프링

목록 보기
8/9
post-thumbnail

1. 인메모리 유저 추가하기

  • Spring Boot - Spring Security에서 하나의 유저만 추가한다면 프로퍼티 설정을 통해서 추가할 수 있다
spring:
  security:
    user:
      name: user
      password: 123!
      roles: USER
  • 하지만 프로퍼티 파일을 통해서는 오직 한명만 추가할 수 있기 때문에, 여러명을 추가하려면 WebSecuityConfigurerAdapterconfigure 메소드를 오버라이딩 해야한다
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("user").password("user123").roles("USER").and()
            .withUser("admin").password("admin123").roles("ADMIN");
    }

2. Prefix 미설정으로 인한 로그인 실패

  • 하지만 이때 비밀번호를 인코딩하지 않고 평문을 설정한다면, DelegatingPasswordEncoder 클래스의 내부 클래스인 UnmappedIdPasswordEncodermatches 메소드에 의해 예외가 발생한다.
    // DelegatingPasswordEncoder는 Spring Security 5의 기본 PasswordEncoder이다
    private class UnmappedIdPasswordEncoder implements PasswordEncoder {
        ...

        public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) {
            String id = DelegatingPasswordEncoder.this.extractId(prefixEncodedPassword);
            throw new IllegalArgumentException("There is no PasswordEncoder mapped for the id \"" + id + "\"");
        }
    }
  • 이를 해결하기 위해서는 prefix가 있어야한다. DelagatingPasswordEncoder 클래스는 다양한 해시 알고리즘PasswordEncoder를 제공하는데, 알고리즘에 맞게 인코더를 선택하기 위해 패스워드 앞에 prefix가 있어야한다. DelagatingPasswordEncoder는 기본적으로 bcrypt를 사용한다
{noop}password123
{bcrypt}$2a$12$0n.nKp3ZY8kmoZMY6jdDi.e6bo.Q8.jPxmvhWl0QHLR6H/qY.a/J.
... 등등 ...
  • 일단 아무런 해싱을 안한다면 "{noop}"을 아래처럼 추가할 수 있다
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("user").password("{noop}user123").roles("USER").and()
            .withUser("admin").password("{noop}admin123").roles("ADMIN");
    }

3. PasswordEncoder.upgradeEncoding()

  • PasswordEncoder 인터페이스는 보안 향상을 위해 다시 인코딩 해야한다면 true를 반환하는 upgradeEncoding() 메소드를 제공한다. 기본 구현으로는 항상 false를 반환하지만 InMemoryUserDetailsManger를 사용한다면, 최초 로그인 성공시 noop에서 bcrypt로 인코더가 변경된다
	@Override
	protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
			UserDetails user) {
		boolean upgradeEncoding = this.userDetailsPasswordService != null
				&& this.passwordEncoder.upgradeEncoding(user.getPassword());
		if (upgradeEncoding) {
			String presentedPassword = authentication.getCredentials().toString();
			String newPassword = this.passwordEncoder.encode(presentedPassword);
			user = this.userDetailsPasswordService.updatePassword(user, newPassword);
		}
		return super.createSuccessAuthentication(principal, authentication, user);
	}
profile
편하게 읽기 좋은 단위의 포스트를 추구하는 개발자입니다

0개의 댓글