
웹 개발을 하다보면 언제나 보안과 관련된 일련의 처리 로직을 고려하고 요구사항에 맞는 서비스를 구현한다.
대부분의 웹 서비스에서는 인증, 인가 단계부터 보안 관련 기능까지 공통적으로 들어가는 요소가 많고
이를 매번 프로젝트 개발 시마다 고려하여 직접 작성하는 것은 효율적이지 않다.
무엇보다 핵심 비즈니스 로직과 관련이 없는 경우가 많다.
이번 포스트에서는 Spring을 통해 웹 개발을 진행할 때 개발자가 보안 관련 로직 처리에 소요되는 비용을 줄이고
핵심 비즈니스 로직에 집중할 수 있도록 도와주는 Spring Security의 기본 개념에 대해 다루어보려한다.
Spring Security가 무엇인지 알아보기 전에 사전에 알아두어야 하는 관련 개념들에 대해서 정리하려한다.
인증 (Authentication)
인증(Authentication)이란 간략하게 리소스를 요청하는 대상이 누구인지를 판별하는 과정을 말한다.즉, 신원을 확인하는 과정을 말하며 웹사이트에 들어온 사용자가 로그인하기 위해
아이디와 비밀번호를 입력하고 요청하는 경우가 이러한 인증 절차에 해당한다.
인가 (Authorization)
인가(Authorization)란 인증된 사용자가 특정 리소스에 접근할 수 있는 권한을 의미한다 볼 수 있다.사용자가 게시글을 삭제한다거나, 수정하고 싶어 요청을 보냈다 가정하면
해당 요청에 대한 처리를 수행할 때 이 사용자가 권한이 있는지 확인하는 것이다.
HTTP 무상태성 (Http Stateless)
웹 통신 프로토콜인 HTTP의 특징 중 하나인 무상태성(Stateless)은
서버가 클라이언트의 이전 요청을 기억하지 못한다는 것이다.이러한 특징은 기존 요청을 보낸 사용자가 어떤 상태를 가지는지 알 수 없기에
기존 상태를 기반으로 작업을 수행해야하는 로직의 경우 문제가 발생할 수 있는데
이를 세션, 쿠키, JWT 등과 같은 기술들을 활용해 기억하고 해결한다.
추가적으로 서블릿(Servlet)과 서블릿 컨테이너(Servlet Container)에 대한, 배경 지식이 필요한데
이는 기존 포스트에서 다루었기에 이번 포스트에서는 별도로 다루지 않도록 한다.
위 배경지식들이 필요한 이유는 Spring Security가 수행하는 대부분의 작업이 다음과 맞닿아 있기 때문이다.
무상태성을 가지는 웹 프로토콜에서 기존 인증 사용자를 어떻게 기억하고,
다음 요청에서 어떻게 알아보며,
어떤 권한을 가지고 해당 요청을 보내는지 확인하는 절차
추가적으로 서블릿 관련 개념의 경우, Spring Security가 Spring에서 어떻게 동작하는지
내부 과정을 이해하기 위해 필요한 배경지식이 된다.
앞선 배경지식을 살펴보며 어느정도 예상이 가능하고, 이름에서부터도 유추가 가능하겠지만
Spring Security 다음과 같이 정의할 수 있다.
스프링 기반 어플리케이션의 인증(Authentication), 인가(Authorization)를 포함
보안 기능을 처리하는 하위 프레임워크
스프링 시큐리티가 수행하는 일은 한 줄로 다음처럼 설명할 수 있다.
지금 요청을 보낸 사용자가 누구이고, 그 사용자가 이 작업을 할 자격이 있는가?
- Authentication
- Authorization
인증과 인가 이외에도 스프링 시큐리티는 스프링 프레임워크를 통해 제작한 웹 어플리케이션에서
보안 관련한 것을 모두 관리해주는 역할을 수행한다.
Spring Security의 경우, Spring MVC의 영역인 컨트롤러나 디스패처 서블릿에서 실행되는 것이 아니라
그보다 앞선 단계인 서블릿 필터(Servlet Filter)에서 동작한다.
서블릿 필터는 요청이 서블릿(이때는 디스패처 서블릿)에 도달하기 전에 먼저 요청을 가로채어 필터의 기능을 수행하며 서블릿 컨테이너에 의해서 관리된다.
이때 여러 필터가 순서대로 연결되어 요청을 처리하는 구조를 필터 체인(Filter Chain)이라 한다.
Spring Security는 이 필터 체인 내부에 자신이 사용하는 보안 필터들을 등록해두고,
클라이언트의 요청이 컨트롤러에 도달하기 전에 인증, 인가와 같은 보안 공통 관심사를 먼저 수행할 수 있다.
Filter, Interceptor, AOP의 동작 시점 차이
- Filter: DispatcherServlet보다 앞단, 컨테이너 레벨에서 동작
- Interceptor: DispatcherServlet과 Controller 사이 (스프링 MVC 수준)
- AOP: 메서드 실행 전/후/주변 (메서드 호출 수준)
스프링 시큐리티의 경우 어플리케이션 전체의 보안을 책임져야하기에,
스프링 MVC에 종속되지 않고 가장 앞에서 모든 요청을 검사할 수 있는 필터 기반으로 설계한 것이다.

WAS(Web Application Server)란
동적인 웹 애플리케이션 로직을 실행하는 서버를 말한다.
클라이언트의 요청을 받아 애플리케이션 코드를 실행하고, 그 결과를 HTTP 응답으로 반환한다.예:
Tomcat,Jetty,Undertow,JBoss/WildFly
- vs Web Server
- Web Server는 주로 HTML, CSS, JS, 이미지 같은 정적 리소스를 제공한다.
- 예:
Nginx,Apache HTTP Server
서블릿 컨테이너가 관리하는 서블릿 필터에서 Spring Security가 동작한다.
Spring Security는 자체 보안 필터들을 필터 체인에 등록해두고,
요청이 DispatcherServlet에 도달하기 전에 인증과 인가 같은 보안 검사를 수행한다.
필터(필터 체인)를 모두 통과한 요청은 DispatcherServlet으로 이동한다.
이후 시점부터 요청 처리는 본격적으로 Spring MVC 영역에서 진행된다.

1. 클라이언트의 요청 수신
클라이언트의 요청은 Tomcat 같은 WAS에 도착하고, WAS 내부의 Servlet Container가 요청 처리를 시작한다.
단, 실제 운영 환경에서는 Servlet Container 앞에 Nginx, 로드밸런서 같은 장비가 있을 수 있다.
2. Servlet Filter Chain
Servlet Container가 받은 요청은 Servlet으로 바로 전달되지 않고,
먼저 Servlet Filter Chain을 거친다. Filter Chain은 여러 Servlet Filter가 순서대로 연결된 구조이며,
각 Filter는 요청을 다음 Filter로 넘기거나 중간에 차단할 수 있다.
3. Filter, DelegatingFilterProxy
Filter Chain 안에는 인코딩, CORS, 로깅 등 공통 처리를 위한 Filter들이 존재할 수 있다.
Spring Security를 사용하는 경우, 이 Filter Chain 안에 DelegatingFilterProxy가 등록된다.
DelegatingFilterProxy는 Spring Security의 실제 보안 로직을 직접 수행하기보다는,
Servlet Container와 Spring Container 사이를 연결하는 프록시 역할을 한다.
4. FilterChainProxy
Servlet Container는 Spring Container가 관리하는 Bean을 직접 알지 못한다.
따라서 Servlet Filter Chain에는 DelegatingFilterProxy를 등록해두고, 이 프록시가
Spring Container 안의 springSecurityFilterChain Bean에게 요청 처리를 위임한다.
Spring Security에서 이 Bean은 보통 FilterChainProxy 타입의 단일 객체이다.
FilterChainProxy는 내부에 여러 SecurityFilterChain을 가지고 있으며,
현재 요청에 맞는 SecurityFilterChain을 선택한 뒤 그 안의 보안 필터들을 실행한다.
5. SecurityFilterChain
SecurityFilterChain은 특정 요청에 적용할 Spring Security 보안 필터들의 묶음이다.
개발자가 작성한 SecurityConfig의 설정을 바탕으로 생성되며,
내부에는 인증, 인가, CSRF, 로그아웃 등과 관련된 여러 보안 필터들이 순서대로 들어 있다.
요청은 선택된 SecurityFilterChain 안의 필터들을 순서대로 통과하고,
보안 검사를 통과하면 이후 DispatcherServlet으로 전달된다.