Spring Security - Filters ( DelegatingFilterProxy, FilterChainProxy )

이번 글에서는 Spring Security Filter Chain 에 대해서 정리를 하려고 한다.



Spring Security web infrastructure 는 Servlet 

filter 기반이다.  

아래의 이미지를 보면, http request 가 어떻게 처리 될 지 명백하게 이해할 수 있을것이다. 

Client 는 Application 으로 요청을 보낸다. 그리고 해당 요청은 어떤 filter 들과 어떤 servlet 이 적용되야 하는지 request URI 에 따라서 판별된다. 최대 하나의 servlet 은 하나의 request 만 처리할 수 있지만, filter 는 chain 을 이루고 순서가 지정되며 실제로 request 자체를 처리할 때 filter 가 나머지 chain 이 처리 되지 않도록 할 수 있다. filter 는 이후에 적용될 filter 및 servlet 에 사용 될 request 와 response 를 수정할 수도 있다. 따라서 filter chain 의 순서는 매우 중요하다.

Spring Boot 에서는 두 가지 메커니즘을 통해 filter chain 을 관리한다.
  1. Filter Type 의 @Beans 은 @Order 를 가지거나 Ordered 를 구현한다.
    one is that @Beans of type Filter can have an @Order or implement Ordered
  2. Filter 들이 API 의 일부로서 순서를 갖는 FilterRegistrationBean 의 일부가 될 수 있다.
    the other is that they can be part of a FilterRegistrationBean that itself has an order as part of its API.
기존의 Spring Security 에서 존재하는 Filters 들은 서로 간의 순서를 쉽게 알릴 수 있도록 상수를 가진다.
(e.g. the SessionRepositoryFilter from Spring Session has a DEFAULT_ORDER of Integer.MIN_VALUE + 50, which tells us it likes to be early in the chain, but it doesn’t rule out other filters coming before it).

Spring Security 는 하나의 Filter 만 사용한다. 해당 Filter Type 은 FilterChainProxy 이다. 


Spring Boot Application 에서 Security Filter 는 ApplicationContext 의 @Bean 이며 모든 요청에 기본적으로 적용된다.
SecurityProperties.DEFAULT_FILTER_ORDER 에 의해 정의 된 위치에 설치되며, FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER 에 의해 고정된다.
컨테이너 보안의 관점에서 보면 Spring Security Filter 는 Single Filter 이지만, 내부에는 각각 특별한 역할을 하는 추가 Filter 가 있다.

실제로 Spring Security Filter 에는 간접 계층이 하나 더 있다. 일반적으로 컨테이너에 DelegatingFilterProxy 로 설치 된다. DelegatingFilterProxy 는 항상 @Bean 인 FilterChainProxy 에 위임한다. 보통 @Bean name 은 springSecurityFilterChain 이다. FilterChainProxy 는 내부적으로 Filter Chain 으로 내부에 배열 된 모든 보안 로직을 포함한다. 모든 필터는 동일한 API 를 가지며 (모두 Servlet Spec 을 따르는 Filter Interface 를 구현 함) 나머지 chain 을 거부 할 수 있다.


Spring Security 는 여러 개의 Filter Chain 을 가질 수 있다.

동일한 최상위 레벨 FilterChainProxy 에서 Spring Security 의해 관리되는 여러 개의 Filter Chain 이 있을 수 있다. 아래의 이미지를 보자. uri path 에 따라 filter chain 을 dispatch 하고 있다.

커스텀 security configuration 이 아닌 vanilla security configuration 에서는 보통 6개의 filter chain 을 구비하고 있다.
  • static resource patterns 을 무시하는 chain 이다. ( /css/** , /images/** )
  • 그리고 error view 나타내는 /error path ( path 는 security.ignored from the SecurityProperties configuration bean 으로 조절이 가능하다.)
  • /** 와 같이 모든 path 를 아우르며 인증, 권한 부여, 예외 처리, 세션 처리, 헤더 작성 등을 위한 논리를 포함한다. 기본적으로 해당 chain 에는 총 11개 의 filter 가 있지만 일반적으로 어떤 filter 가 언제 사용되는지 사용자는 걱정할 필요가 없다.

아래에는 필자가 직접 디버깅을 해보았다.

아래의 이미지는 DelegatingFilterProxy 의 doFilter() 메서드이다.
this.delegate 에 FilterChainProxy 을 대입하고 invokeDelegate() 메서드를 통해서 FilterChainProxy 에게 위임하고 있다.

아래 debug stack trace 을 통해 확인할 수 있다. ApplicationFilterChain 의 5번 째 Filter 에 DelegatingFilterProxy 가 지정되어 있음을 알 수 있다. DelegatingFilterProxy 는 FilterChainProxy 에게 위임한다. 

아래의 사진은 FilterChainProxy 의 doFilter 메서드 이다.

FilterChainProxy 는 아래의 이미지와 같이 총 9개의 Filter 를 가지고 있다. 
FilterChainProxy request 의 path 에 맞게 설정된 filter chain (현재는 9개의 filter) 로 dispatch 하고, 해당 filter 들의 doFilter() 메서드를 호출한다.

이번 글에서는 Spring Security 의 Filter 메커니즘에 대해서 정리해보았다.

댓글

이 블로그의 인기 게시물

About Kafka Basic

About JVM Warm up

About ZGC

Spring Boot Actuator readiness, liveness probes on k8s

About G1 GC

sneak peek jitpack

About idempotent

C 언어 구조체의 포인터 멤버 변수

Synology NAS에 MariaDB 10에 Mysql workbench로 원격접속하기

About Websocket minimize data size and data transfer cost on cloud