A Review of Filters
Spring security support는 Servlet Filter 기반이기 때문에 일반적으로 처음에 Filter의 역할을 찾아보는 것이 유용하다. 아래는 하나의 HTTP 요청을 위한 handler의 전형적인 계층을 보여준다.
클라이언트가 애플리케이션에 요청을 보내면, 컨테이너는 요청 URI를 기반으로 한 HttpServletRequest를 처리해야 하는 Filter instance와 Servlet을 포함한 FilterChain을 생성한다. Spring MVC application에서의 Servlet은 DispatcherServlet이다. 많아 봐야 하나의 Servlet은 하나의 HttpServletRequest와 HttpServletResponse를 다룰 수 있다. 그러나 둘 이상의 Filter를 사용할 수 있다.
- 아래로 흐르는 Filter instance 또는 호출 된 Servlet을 방지해라. 이번 경우에는 전형적으로 Filter가 HttpServletResponse를 작성한다.
- 아래로 흐르는 Filter instance와 Servlet으로 사용되는 HttpServletRequest와 HttpServletRensponse를 수정하라.
Filter의 힘은 인자로 들어오는 FilterChain으로부터 온다.
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
}
Filter는 오직 아래 방향의 Filter instance와 Servlet에 영향을 주기 때문에 각 Filter가 호출되는 순서는 매우 중요하다.
DelegatingFilterProxy
Spring은 Servlet container의 life cycle과 Spring의 ApplicationContext 사이를 잇도록 허용하는 DelegatingFilterProxy라는 이름의 Filter 구현체를 제공한다. Servlet container는 그들 자신의 표준을 사용하여 Filter instance들을 등록하지만, Spring-defined Beans는 모른다. 당신은 standard Servlet container mechanisms을 통하여 DelegatingFilterProxy를 등록할 수 있지만 Filter를 구현한 Spring Bean에게 모든 작업을 위임한다.
여기 어떻게 DelegatingFilterProxy가 Filter instances와 FilterChain에 적용되는지 보여주는 그림이 있다.
DelegatingFilterProxy는 ApplicationContext로부터 Bean Filter0를 찾으면 Bean Filter0를 호출한다. 다음 목록은 DelegatingFilterProxy pseudo code를 보여준다.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
Filter delegate = getFilterBean(someBeanName);
delegate.doFilter(request, response);
}
- 천천히 스프링 Bean으로 등록된 Filter를 얻으세요. 예를 들어 DelegatingFilterProxy에 있는 delegate는 Bean Filter0의 인스턴스입니다.
- Spring Bean에게 일을 위임해라.
DelegatingFilterProxy의 또다른 이점은 Filter bean instance 조회를 지연시킨다. 이는 컨테이너가 스스로 시작할 수 있기 전에 Filter instance를 등록하는데 필요하기 때문에 중요하다. 그러나 일반적으로 Spring은 Filter instance가 등록이 요구되는 이후까지 완료되지 않는 Spring Beans을 적재하기 위해 ContextLoaderListener를 사용한다.
FilterChainProxy
Spring security's Servlet support는 FilterChainProxy 안에 포함되어있다. FilterChainProxy는 SecurityFilterChain을 통해 많은 Filter instances를 위임하는 것을 허용하는 Spring Security에 의해 제공되는 특별한 Filter이다. FilterChainProxy는 Bean이기 때문에, 일반적으로 DelegatingFilterProxy 안에 wrapping 되어 있다.
아래는 FilterChainProxy의 역할에 대한 이미지이다.
SecurityFilterChain
SecurityFilterChain은 Spring Security Filter instances가 현재 요청을 위해 호출되어야 하는 것을 결정하기 위해 FilterChainProxy에 의해 사용된다.
아래는 SecurityFilterChain의 이미지이다.
SecurityFilterChain 안에 있는 Security Filters 는 일반적으로 Beans이지만, 그들은 DelegatingFilterProxy 대신 FilterChainProxy와 함께 등록된다. FilterChainProxy는 Servlet container나 DelegatingFilterProxy와 함께 즉시 등록하는 많은 이점을 제공한다.
첫 째로, 이는 모든 Spring Secuirty's Sevlet support를 위한 시작점을 제공한다. 때문에, 만약 Spring Security's Servlet support의 문제를 분석-해결하려 한다면, FilterChainProxy 안에 debug point를 추가하는 것은 좋은 출발점이다.
둘 째로, FilterChainProxy는 Spring Security 이용의 중간이기 때문에, 이는 선택적으로 보이지 않는 일들을 수행할 수 있다. 예를 들어, 메모리 누수를 피하기 위해 SecurityContext를 비우는 일이 있다. 이는 또한 확실한 공격 유형에 대항하여 애플리케이션을 보호하기 위해 Spring Security's HttpFirewall을 사용한다.
추가로, 이는 SecurityFilterChain이 호출되어야 할 때 결정에서 더 많은 유연함을 제공한다. Servlet container에서 Filter instances는 URL 하나의 기반으로 호출된다. 그러나 FilterChainProxy는 RequestMatcher interface를 사용함으로써 HttpServletRequest에서 실행을 결정할 수 있다.
아래는 여러 SecurityFilterChain instances에 대해 보여준다.
Multiple SecurityFilterChain 그림에서 FilterChainProxy는 SecurityFilterChain이 사용 되어야 하는 것에 대해 결정한다. 오직 일치하는 처음 SecurityFilterChain만 호출됩니다. 만약 /api/messages/ URL로 요청 되었다면, 그것은 처음 /api/**의 패턴으로SecurityFilterChain0에서 일치하며, 이는 오직 SecurityFilterChain0에서 호출되며, 심지어 또한 SecurityFilterChainN과도 일치한다. 만약 /messages/ URL로 요청 되었다면 이는 SecurityFilterChain0의 /api/** 패턴과 일치하지 않으며, FilterChainProxy는 각 SecurityFilterChain을 계속해서 시도한다. 다른 SecuritFilterChain instances와 일치하지 않는다고 가정하면, SecurityFilterChainN이 호출된다.
SecurityFilterChain0이 가지고 있는 세 개로 구성되어 있는 security Filter instances에 주목해라. 이에 반해 SecurityFilterChainN은 네 개로 구성되어 있는 security Filter instances를 가지고 있다. 각각의 SecurityFilterChain이 유일할 수 있고, 독립적으로 구성될 수 있는 것에 주의하는 것이 중요하다. 만약 애플리케이션이 Spring Security가 특정 요청들을 무시하길 원한다면 사실 SecurityFilterChain은 sucurity Filter instances를 하나도 가지고 있지 않을지도 모른다.
'보안(인증, 인가, Spring security)' 카테고리의 다른 글
[Spring security] 인가 - 특정 리소스 마다 권한 설정하기 (0) | 2024.02.13 |
---|---|
인증과 인가 (0) | 2024.02.09 |