Each of the supported mechanisms for reading a username and password can use any of the supported storage mechanisms:
Simple Storage with In-Memory Authentication
Relational Databases with JDBC Authentication
Custom data stores with UserDetailsService
LDAP storage with LDAP Authentication
UserDetails는 UserDetailsService에 의해 반환됩니다. DaoAuthenticationProvider는 이 UserDetails를 검증하고, 이후 UserDetailsService에서 반환된 UserDetails가 principal로 설정된 Authentication 객체를 반환합니다.
좋습니다. Spring Security에서의 UserDetailsService와 DaoAuthenticationProvider의 흐름을 하나씩 단계별로 자세히 설명해드릴게요.
UserDetailsService 인터페이스
UserDetailsService는 사용자의 인증 정보를 가져오는 역할을 합니다. 이 인터페이스를 구현한 클래스에서 loadUserByUsername 메소드를 통해 사용자의 ID(예: 이메일, 사용자명)를 기반으로 UserDetails 객체를 반환합니다. UserDetails에는 사용자의 ID, 비밀번호, 권한 등의 인증에 필요한 정보가 담겨 있습니다.
UserDetails 인터페이스
UserDetails는 Spring Security에서 사용자의 세부 정보를 담고 있는 객체로, 계정의 비밀번호, 권한, 계정의 활성 상태, 잠김 여부 등의 정보를 포함합니다. 이 정보를 바탕으로 인증을 처리하는데 사용되며, 이 UserDetails 객체는 이후 Authentication 객체의 principal로 설정됩니다.
DaoAuthenticationProvider
DaoAuthenticationProvider는 Spring Security에서 제공하는 기본 인증 제공자(Provider) 중 하나로, UserDetailsService를 통해 가져온 사용자 정보를 기반으로 사용자의 인증을 처리합니다. 이 DaoAuthenticationProvider는 다음 과정을 통해 인증을 수행합니다.
DaoAuthenticationProvider는 UserDetailsService를 호출하여 입력받은 사용자 ID로 UserDetails를 조회합니다.UserDetails에 있는 비밀번호와 입력받은 비밀번호를 비교하여 일치하는지 검증합니다. 비밀번호 검증에 성공하면 다음 단계로 넘어갑니다.Authentication 객체를 생성하고, 이 Authentication 객체의 principal 필드에 UserDetails 객체를 설정합니다. 이 Authentication 객체는 이제 사용자 정보를 담고 있는 상태입니다.Authentication 객체 반환
DaoAuthenticationProvider는 검증을 마친 Authentication 객체를 반환합니다. 이 객체는 principal로 UserDetails를 포함하고 있어, 이후 SecurityContextHolder에 저장되어 애플리케이션의 다른 부분에서 현재 로그인한 사용자의 정보에 접근할 수 있게 됩니다.
이 과정을 통해 UserDetailsService가 사용자 정보를 조회하고, DaoAuthenticationProvider가 이를 기반으로 검증한 후 Authentication 객체를 반환함으로써 인증이 완료됩니다. Spring Security는 이렇게 검증된 Authentication 객체를 SecurityContext에 저장하여 사용자 정보를 관리하게 됩니다.
Spring Security에서 CredentialsContainer 인터페이스는 사용자의 자격 증명(예: 비밀번호)을 안전하게 관리하기 위한 표준을 제공합니다. 이 인터페이스를 구현하면 인증 과정이 끝난 후 민감한 정보(예: 비밀번호)를 메모리에서 제거할 수 있습니다. 이를 통해 메모리 덤프 공격과 같은 잠재적 보안 위협을 완화할 수 있습니다.
인증 과정에서 사용자의 비밀번호는 UserDetails 객체에 저장됩니다. 문제는 인증이 끝난 후에도 이 객체가 애플리케이션의 메모리에 남아 있을 수 있다는 점입니다.
위험 요소:
해결 방법:
CredentialsContainer를 구현하여 인증이 끝난 후 민감한 데이터(예: 비밀번호)를 즉시 제거합니다.public interface CredentialsContainer {
void eraseCredentials(); // 자격 증명을 제거하는 메서드
}
eraseCredentials()는 자격 증명(예: 비밀번호)을 메모리에서 제거하기 위해 호출됩니다.Spring Security에서 사용자 정보를 정의하는 UserDetails 객체에 CredentialsContainer를 추가하여 비밀번호를 안전하게 관리합니다.
public class MyUserDetails implements UserDetails, CredentialsContainer {
private String username; // 사용자 이름
private String password; // 비밀번호 (자격 증명)
// UserDetails의 필수 메서드 구현
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
// 기타 UserDetails 메서드...
// CredentialsContainer 메서드 구현
@Override
public void eraseCredentials() {
this.password = null; // 비밀번호를 안전하게 제거
}
}
UserDetails 객체가 생성됩니다.ProviderManager(Spring Security의 AuthenticationManager 기본 구현)가 eraseCredentials()를 호출합니다.password 필드가 null로 설정되어 메모리에서 삭제됩니다.사용자 정보를 캐시하는 애플리케이션에서는 추가적인 보안 조치가 필요합니다.
UserDetails 복사본을 반환합니다.public class SafeUserDetails extends MyUserDetails {
public SafeUserDetails(String username) {
super(username, null); // 비밀번호를 null로 설정
}
}
Spring Security의 DaoAuthenticationProvider는 UserDetails를 기반으로 인증을 처리합니다. 이 과정에서:
UserDetails에서 제공된 비밀번호와 데이터베이스의 비밀번호를 비교합니다.AuthenticationManager가 eraseCredentials()를 호출합니다.DaoAuthenticationProvider
UserDetails 객체를 생성하여 반환합니다.AuthenticationManager (ProviderManager)
eraseCredentials()를 호출하여 민감한 데이터를 제거합니다.즉시 삭제
자동 호출 설정
ProviderManager가 eraseCredentials()를 자동으로 호출하도록 설정해야 합니다. 일관된 적용
UserDetails 클래스에서 CredentialsContainer를 구현하고, 민감한 데이터를 관리하는 동일한 표준을 따르세요.Spring Security의 CredentialsContainer 인터페이스는 인증 프로세스 완료 후 비밀번호와 같은 민감한 데이터를 안전하게 제거할 수 있도록 설계되었습니다. 이를 올바르게 구현하고 활용하면 메모리 내 데이터 노출 위험을 크게 줄이고, 보안 수준을 높일 수 있습니다.
이를 통해 애플리케이션이 안전한 인증 체계를 유지하고, 잠재적인 데이터 유출을 예방할 수 있습니다.