Spring security 내부구조와 PasswordEncoder

패스트캠퍼스 Spring Security 강의 정리

인증 & 인가

  • 인증 (Authentication)
    • 사용자가 누구인지 확인하는 절차
    • 로그인
  • 인가 (Authorization)
    • 인증 이후에 리소스에 대한 권한 통제
    • 클라이언트가 요청한 작업이 허가된 작업인지 확인하는 절차

SecurityContextHolder

  • SecurityContextHolder
    • SecurityContext를 제공하는 static 메소드(getContext) 지원
    • 내부에 SecurityContext
  • SecurityContext
    • 접근 주체와 인증에 대한 정보를 담고 있는 context
    • 내부에 Authentication
  • Authentication
    • Principal과 GrantAuthority 제공
    • 인증이 이루어지면 해당 authentication 저장됨
  • Principal
    • 사용자에 해당하는 정보
    • 대부분 Printipal로 UserDetails 반환
  • GrantAuthority
    • ROLE_ADMIN, ROLE_USER 등 Principal이 가지는 권한을 나타냄
    • prefix로 ROLE_이 붙음
    • 인증 이후에 인가가 필요할 때 사용
    • 여러 권한이 있을 수 있으므로 Collection<GrantedAuthority> 형태로 제공

Spring Security 내부 구조

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

SecurityContext context = SecurityContextHolder.getContext();	// Security Context

Authentication authentication = context.getAuthentication(); // Authentication

authentication.getPrincipal(); // Principal
authentication.getAuthorities(); // GrantAuthority
authentication.getCredentials();
authentication.getDetails();
authentication.isAuthenticated();

ThreadLocal

  • WebMVC 기반으로 대부분의 경우 하나의 요청에 하나의 thread 생성
  • ThreadLocal을 사용하여 각 thread마다 고유한 공간을 가지며 SecurityContext 저장

SecurityContext 공유 전략

  • MODE_THREADLOCAL
    • ThreadLocalSecurityContextHolderStrategy 사용
    • ThreadLocal 사용
    • 같은 thread 안에서 SecurityContext 공유
    • 기본 설정
  • MODE_INHERITABLETHREADLOCAL
    • InheritableThreadLocalSecurityContextHonlderStrategy 사용
    • InheratableThreadLocal 사용
    • 자식 thread도 SecurityContext 공유
  • MODE_GLOBAL
    • GlobalSecurityContextHolderStrategy 사용
    • Global 설정
    • 애플리케이션 전체에서 SecurityContext 공유

PasswordEncoder

  • 회원가입할 때 받은 비밀번호는 해시 함수로 암호화해서 저장
  • 로그인할 때의 비밀번호를 같은해시 함수로 암호화
  • 저장된 비밀번호와 비교 후, 동일하면 같은 암호로 인지
  • PasswordEncoder 인터페이스
public interface PasswordEncoder {
  /**
  * @param rawPassword 평문 비밀번호
  * @return 암호화된 비밀번호
  */
  String encode(CharSequence rawPassword);
  
  /**
  * @param rawPassword 평문 비밀번호
  * @param encodedPassword 암호화된 비밀번호
  * @return rawPassword 암호화한 값과 encodedPassword 일치 여부
  */
  boolean matches(CharSequence rawPassword, String encodedPassword);
  
  /**
  * @param encodedPassword 암호화된 비밀번호
  * @return encodedPassword가 다시 인코딩 됐으면 true, 아니면 false
  */
  default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}
}

PasswordEncoder 전략

  • NoOpPasswordEncoder
    • 암호화하지 않고 평문 사용
  • BcryptPasswordEncoder
    • Bcrypt 해시 함수 사용
    • Bcrypt는 패스워드 저장 목적으로 설계됨
    • 무작위로 여러번 시도하는 해킹 방지를 위해 의도적으로 암호를 확인할 때 느리게 설정
    • 강도 설정 가능하며 강도가 높을 수록 오랜 시간 소요
  • Pbkdf2Password
    • 미국표준기술연구소(NIST)에 의해 승인된 알고리즘으로 미국 정부 시스템에서도 사용
  • ScryptPasswordEncoder
    • Pbkdf2와 유사
    • 해커가 무작위로 비밀번호를 맞추려 시도할 때 메모리사용량을 늘리거나 줄여서 느린 공격을 실행할 수 밖에 없도록 함
    • 공격이 매우 어렵고 Pbkdf2보다 안전
    • 보안에 아주 민감한 경우에 사용
종류 예시
NoOpPasswordEncoder
(Deprecated)
{noop}password
BcryptPasswordEncoder {bcrypt}$2a$12$9KGvrW28gpdQ0ll.dqoZv.nHGSZlUNJ1KOzHRFUh4rnf1FYWe1RXW
StandardPasswordEncoder
(Deprecated)
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
Pbkdf2PasswordEncoder {pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc
SCryptPasswordEncoder {scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/ 9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/ 1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=