Spring security 내부구조와 PasswordEncoder
03 Aug 2022패스트캠퍼스 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>
형태로 제공
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= |