본문 바로가기
👨‍💻 프로그래밍/🔒 보안

스프링 서큐리티(Spring Security) 구조 이해하기

by 개발자 진개미 2023. 4. 11.
반응형

스프링 서큐리티 (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가 해야 할 역할도 명확해집니다.

 

  1. HTTP 요청을 받으면 그 요청을 가로채서 보안정보가 있는지 확인하고 없거나 틀리면 요청 거부하기
  2. DB에 있는 유저 정보Principal / Credential이 일치하는 지 확인
  3. 유저정보를 어딘가에 저장해 뒀다가 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가 요청을 받았을때 인증/인가를 처리하는 흐름입니다.

 

  1. 요청을 가로채서 FilterChain에 통과시킴. 여기서 인증/인가 수행
  2. HTTP 요청에서 Principal, Credential 받아와서 Authentication 객체 만듬
  3. AuthenticationManger에 Authentication 객체 넘겨줌.
  4. AuthenticationManager는 적절한 AuthenticationProvider 호출해서 Authentication 객체를 인증함.
  5. AuthenticationProvider는 UserDetailsService에서 UserDetails 정보 받아와서 Authentication 안의 인증 정보와 일치하는지 확인
  6. 인증된 Authentication 객체, GrantedAuthorities 등을 SecurityContextHolder를 사용해서 SecurityContext에 저장
  7. 유저 정보가 필요할 때 마다 SecurityContextHolder를 통해서 받아올 수 있음

반응형