Servlet 애플리케이션의 Spring Security(v 5.7.9)에 대한 글입니다.
💡 보안(인증, 인가, 일반적 공격 방어)을 담당하는 스프링 하위 프레임워크
웹에서 인증(Authentication)은 웹 애플리케이션에 접근하려는 사용자의 신분을 확인하는 과정입니다. 특정 리소스 접근, 작업 시 신분이 증명된 사용자만 접근할 수 있도록 하는 기본적인 보안 메커니즘으로, 민감한 정보를 보호하고 무단 접근을 방지합니다. 주로 아이디와 패스워드를 사용해 사용자를 확인합니다.
웹에서 인가(Authorization)는 인증된 사용자가 특정 리소스나 작업에 접근할 수 있는 권한을 부여하거나 거부하는 보안 메커니즘으로, 보안을 강화하고 리소스를 보호합니다. 사용자에게 권한 및 역할(Role)을 부여하여 인가를 수행할 수 있습니다.
Spring Security가 웹 상에서 일반적인 공격을 방어하기 위해 제공하는 기능은 다음과 같습니다.
CSRF(Cross Site Request Forgery) 방어
CSRF 토큰을 제공하고, HTTP Post 요청 시 CSRF 토큰을 확인하여 유효한 요청인지 검사합니다.
Security HTTP Response Headers
보안을 위한 응답 헤더를 설정할 수 있습니다.
ex) X-Frame-Options, X-XSS-Protection, Cross-Origin Policies 등
HTTP
클라이언트가 HTTPS가 아닌 HTTP로 요청하는 경우, HTTPS로 리다이렉션할 수 있습니다.
HttpFirewall
Servlet Spec에서 servletPath, pathInfo를 정확히 정의하지 않아 생길 수 있는 URL을 통한 공격을 방어합니다.
클라이언트가 애플리케이션에 요청을 보내면, 컨테이너는 요청 URI를 기반으로 HttpServletRequest를 처리하는 필터와 서블릿을 포함하는 FilterChain을 생성합니다.
참고) Spring MVC 애플리케이션에서 서블릿은 DispatcherServlet의 인스턴스이므로 대부분 하나입니다.

Filter를 거치며 요청에 대한 사용자 인증, 로깅 등 작업을 수행하고, Servlet은 해당 요청에 대한 로직을 처리합니다. 로직 수행 후 사용자에게 응답을 보낼 때 다시 Filter를 거치며 추가적인 작업을 수행할 수 있습니다.
// Filter의 수도 코드
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before the rest of the application
chain.doFilter(request, response); // invoke the rest of the application
// do something after the rest of the application
}
서블릿 컨테이너와 ApplicationContext 사이를 연결하는 Spring의 필터 구현체입니다. Spring은 DelegatingFilterProxy를 통해 Spring의 FilterChain들을 Servlet Filter 단에서 사용할 수 있도록 만들었습니다.

DelegatingFilterProxy는 Servlet Filter로 등록되며, Spring에 등록된 Bean Filter에게 모든 작업을 위임합니다.
참고) DelegatingFilterProxy은 Servlet Filter이므로 Spring bean이 아닌 표준 Servlet Filter를 구현합니다.
// DelegatingFilterProxy의 수도 코드
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// Lazily get Filter that was registered as a Spring Bean
// For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
Filter delegate = getFilterBean(someBeanName);
// delegate work to the Spring Bean
delegate.doFilter(request, response);
}
FilterChainProxy는 SecurityFilterChain의 필터들을 실행하는 Spring Security의 필터로, Spring Security의 보안 처리가 시작되는 지점입니다. DelegatingFilterProxy에 기본적으로 설정되는 Spring Bean입니다.

DelegatingFilterProxy 대신 FilterChainProxy에 필터를 등록하면, URL만을 기반으로 필터를 호출하는 서블릿과 달리 RequestMatcher 인터페이스를 활용하여 HttpServletRequest의 모든 항목을 기반으로 필터를 호출할 수 있으므로 요청에 필터를 유연하게 적용할 수 있습니다.
FilterChainProxy에서 요청을 처리할 때 사용해야 하는 Spring Security Filter들을 결정할 때 사용됩니다. FilterChainProxy은 SecurityFilterChain 에 구성된RequestMatcher의 구현체를 기반으로 요청을 처리할 SecurityFilterChain을 선택합니다.

SecurityFilterChain은 여러 개를 등록할 수 있으며, 각 SecurityFilterChain은 별도로 구성될 수 있습니다. SecurityFilterChain이 여러 개인 경우, FilterChainProxy은 일치하는 첫 번째 SecurityFilterChain만 호출합니다. /api/** 경로로 요청이 들어온다면 0번 SecurityFilterChain을, /** 경로로 요청이 들어온다면 n번 SecurityFilterChain 을 호출합니다.
참고) 필터 순서는 요청을 처리하는 순서이므로 매우 중요합니다.
여기에서 Spring Security의 기본 필터 순서를 확인할 수 있습니다.

DelegatingFilterProxy 필터를 서블릿 필터에 등록합니다.DelegatingFilterProxy 필터에 도달합니다.DelegatingFilterProxy는 FilterChainProxy에게 작업을 위임합니다.FilterChainProxy은 SecurityFilterChain을 기반으로 Spring Security Filter들을 실행합니다.