반응형
스프링 서큐리티 (Spring Security)? 그거 어떻게 하는 건데?
Spring Security는 말 그대로 Spring 기반 애플리케이션에 보안을 제공하는 프레임워크입니다.
제공하는 기능은 아래와 같습니다.
- 인증 / 인가 (아래서 설명)
- 일반적인 보안 위협 방어 (CSRF, XSS, SQL Injection)
- 세션(Session) 관리
- 다른 Spring의 프로젝트들과 연동
보안에 관한 기본적인 용어를 알아보자
리소스 | Resource | 보호하고자 하는 대상 |
접근 주체 | Principal | 접근하는 사람 (일반적으로 아이디) |
자격 증명 | Credential | 접근하는 사람이 본인이라는 걸 증명할 수 있는 정보 (일반적으로 비밀번호) |
역할 | Roles | Principal이 가지고 있는 권한 |
인증 | Authentication | 정말 그 사람이 맞는지 판단하는 것 (Principal과 Credential을 기반으로) |
인가 | Authorization | 역할을 바탕으로 어떤 리소스에 접근 가능한지 판단하는것 |
보안의 핵심적인 원리 이해하기
본격적으로 Spring Security를 이해하기 전에, 일반적으로 웹 서비스의 보안을 어떻게 처리하는지 이해해야 합니다.
Client가 올바른 증명(쿠키, 세션, 아이디/비밀번호 등)을 주지 않는 모든 요청은 거부(HTTP 403) 하는 것
- 여기서 클라이언트(Client)는 일반적으로 웹 브라우저로 사이트를 접근하는 우리들을 말합니다.
- 크롬의 개발자 도구(일반적으로는 F12 누르면 나옴)에 들어가면 Cookies, Local Storage, Session Storage 등이 보이실 겁니다. 우리가 웹 사이트에 들어갈 때 마다 브라우저가 서버에 이 정보들을 보내는 겁니다.
- 서버는 클라이언트가 보낸 정보들이 올바른 정보인지 확인하고, 올바른 정보면 접근을 허가합니다.
- 이 정보들을 보낼 때는 HTTPS로 암호화하기 때문에 해커가 중간에 탈취하지 못 합니다.
Spring Security의 핵심 interface 살펴보기
보안의 기본적인 원리를 이해하면, Spring Security가 해야 할 역할도 명확해집니다.
- HTTP 요청을 받으면 그 요청을 가로채서 보안정보가 있는지 확인하고 없거나 틀리면 요청 거부하기
- DB에 있는 유저 정보와 Principal / Credential이 일치하는 지 확인
- 유저정보를 어딘가에 저장해 뒀다가 Spring의 다른 method가 요청할 때 마다 제공하기
이러한 역할 수행하기 위한 Spring Security의 핵심적인 interface입니다.
Filter | 요청을 가로채서 특정 동작을 수행할 수 있음 (Spring Security에서는 보안 관련 동작 수행) |
FilterChain | 여러개의 Filter를 특정 순서대로 배치한 것 |
Authentication | 유저의 아이디, 비밀번호, 권한 등을 저장하는 객체 |
Authentication Provider | 아직 인증 안 된 Authentication을 받아서 (아이디/비밀번호가 맞는 경우) 인증된 Authentication 객체를 반환 |
Authentication Manager | 여러개의 AuthenticationProvider를 가지고 있고, 어떤 AuthenticationProvider를 쓸지 결정 |
User Details | DB 등에 저장될 User 정보를 나타냄 |
Password Encoder | 비밀번호를 인코딩함 (DB에 평문 그대로 저장하면 해킹 당했을때 비밀번호 유출되니깐) |
User Details Service | UserDetails를 가져오기 위한 Service |
Security Context | 보안 관련 정보(Authentication, GrantedAuthories 등) 저장 (Request/Thread 단위로) |
Security Context Holder | SecurityContext를 저장하고 가져오기 위한 Helper Class |
Granted Authority | 유저의 Role(권한)을 나타냄. ROLE_ADMIN 같이, ROLE_로 시작 |
- Filter, FilterChain의 경우 Spring Security가 아닌 Servlet에서 왔지만 Spring Security에서도 핵심적인 역할을 수행합니다.
- Spring Security에서는 interface들을 implement한 다양한 class를 적용시켜 보안을 처리합니다.
- 다양한 요구사항에 맞는 implementation이 있지만, 직접 구현할 수도 있습니다.
요청 가로채서 보안 적용하기 : Filter, FilterChain
유저 정보 저장하고 가져오기 : UserDetails, UserDetailsService
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
public interface UserDetailsService {
UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException;
}
로그인 처리하기 : Authentication, AuthenticationProvider, AuthenticationManager
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated)
throws IllegalArgumentException;
}
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
boolean supports(Class<?> authentication);
}
로그인된 유저 정보 사용하기 : SecurityContext, SecurityContextHolder
public interface SecurityContext extends Serializable {
Authentication getAuthentication();
void setAuthentication(Authentication authentication);
}
public class SecurityContextHolder {
// 생략
static { initialize(); }
private static void initialize() {
initializeStrategy();
initializeCount++;
}
private static void initializeStrategy() {
// 생략
}
public static void clearContext() {
strategy.clearContext();
}
public static SecurityContext getContext() {
return strategy.getContext();
}
public static void setContext(SecurityContext context) {
strategy.setContext(context);
}
}
흐름을 따라가면서 Spring Security 아키텍처 이해하기
마지막으로 정리하자면, Spring Security가 요청을 받았을때 인증/인가를 처리하는 흐름입니다.
- 요청을 가로채서 FilterChain에 통과시킴. 여기서 인증/인가 수행
- HTTP 요청에서 Principal, Credential 받아와서 Authentication 객체 만듬
- AuthenticationManger에 Authentication 객체 넘겨줌.
- AuthenticationManager는 적절한 AuthenticationProvider 호출해서 Authentication 객체를 인증함.
- AuthenticationProvider는 UserDetailsService에서 UserDetails 정보 받아와서 Authentication 안의 인증 정보와 일치하는지 확인
- 인증된 Authentication 객체, GrantedAuthorities 등을 SecurityContextHolder를 사용해서 SecurityContext에 저장
- 유저 정보가 필요할 때 마다 SecurityContextHolder를 통해서 받아올 수 있음
반응형
'👨💻 프로그래밍 > 🔒 보안' 카테고리의 다른 글
API Key를 하드코딩 하면 안 될까? (0) | 2024.07.27 |
---|---|
다양한 로그인 방법을 알아보자 (OAuth, Open ID, OIDC, SSO, SFA, 2FA, MFA, OTP, PassKey) (0) | 2024.02.08 |
망분리 (Network Segregation), 왜 필요할까? (0) | 2023.09.27 |