본문 바로가기

Language & Framework/Spring

스프링 시큐리티의 DelegatingFilterProxy, FilterChainProxy, SecurityFilterChain에 대해 알아보자.

*  Spring Security Refrence Docs/ API/ 소스코드를 참고하여 작성한 글입니다. 개인 공부 목적으로 작성한 것이기에 내용의 정확성을 보장할 수 없습니다.

 

 

 

 

1.FilterChain의 기본 흐름

 

 

 

스프링 시큐리티의 서블릿은 서블릿 필터를 기반으로 한다.

클라이언트가 애플리케이션에 요청을 보내면 컨테이너는 Filter와 Servlet을 포함하는 FilterChain을 만들고, 이들은 요청의 URI를 기반으로 HttpServletRequest를 처리해야 한다.

대개의 경우 서블릿은 하나의 HttpServletRequest와 HttpServletResponse만을 다룰 수 있으나, 연결된 여러 필터를 이용하여 하부에 위치한 필터나 서블릿이 호출되는 것을 막고, 하부 필터나 서블릿이 사용하는 HttpServletRequest혹은 HttpServletResponse를 수정한다.

 

필터는 오직 하부의 필터와 서블릿에만 영향을 줄 수 있기 때문에, 각각의 필터가 순서에 맞게 배치되는 것이 중요하다.

 

 

 

 

 

 

 

2. DelegatingFilterPRoxy

 

 

DelegatingFilterProxy는 스프링에게 Filter Interface의 구현을 위임하는 Servlet Filter의 표준 Prxoy다.

 

스프링은 DelegatingFilterProxy라는 이름의 필터 구현체를 제공하며, 이는 Servlet 컨테이너 생명주기와 Spring ApplicationContext의 징검다리 역할을 수행한다.

서블릿 컨테이너는 필터를 빈으로 등록할 수 없기 때문에 Filter를 구현하는 Spring Bean에게 모든 역할을 위임하고, DelegatingFilterProxy는 현재 사용해야할 필터의 빈을 ApplicationContext에서 검색하여 이를 호출한다.

 

DelegatingFilterProxy의 특별한 점은 Filter bean 인스턴스의 등록을 지연시킬 수 있다는 것이다.

기본적으로 스프링 빈 컨테이너는 컨테이너가 실행되기 전에 Filter 인스턴스를 등록하는 것이 원칙이지만, 스프링은 일반적으로 ContextLaderListener를 사용하여Spring Bean이 Filter 인스턴스가 등록될 필요가 있을 때까지 작동하지 않는 Bean을 불러낸다.

 

DelegatingFilterProxy은 GenericFilterBean을 상속받고 있다.

GenericFilterBean은 ApplicationContext에 종속되지 않으면서도 ServletContext를 통해 빈을 등록하는데 사용된다고 한다. (ServletContext가 WebApplicationContextUtils를 통해 WebApplicationContext에 접근한다.)

 

 

 

초기 어플리케이션 실행 시 별도 설정이 없을 경우 기본 beanName과 WebApplicationContext를 인자로 받아서 생성되며, targetBeanName인 springSecurityFilterChain은 SpringBean에 SpringSecurityFilterChain으로 등록된 빈에게 위임하기 위함이다.

 

 

클라이언트 요청을 받는 시점에 req, res, FiltetChain을 인자로 받아 doFilter 메서드를 호출한다.

이 때 FilterChainProxy에게 권한을 위임하게 된다. 

 

 

 

 

 

 

3. FilterChainProxy

 

 

스프링 시큐리티의 서블릿은 내부적으로 FilterChainProxy를 가진다.

FilterChainProxy는 스프링 시큐리티로부터 제공되는 특별한 Filter로써 많은 Filter 인스턴스를 SecurityFilterChain을 통해 위임할 수 있도록 한다.

FilterChainProxy는 빈이며, 이것은 일반적으로 DelegatingFilterProxy로 래핑된다.

 

FilterChainProxy는 내부의 어떤 필터가 doFilter를 호출하지 않아도 그것을 인정하며, 이 경우 하부에 선언된 필터들은 더 이상 실행되지 않는다.

 

 

DelegatingFilterProxy에게 위임받은 직후의 상태.

 

 

내부적으로 기본적인 방화벽 설정 등을 마치고나면 doFilter로 필터 Chain 내부에서의 흐름이 시작된다.

 

 

 

 

4. SecurityFilterChain

 

 

 

공식 홈페이지를 보면 알겠지만, SecurityFilterChain 항목에 SecurityFilterProxy에 대한 내용이 엄청나게 많이 나온다.

그리고 SecurityFilterChain은 API에도 별다른 글이 없다.. 굳이 항목을 나눠놓고 왜 여기에 SecurityFilterProxy 얘기만 주구장창 적어놨는지는 나도 의문이다..

 

SeucurityFilterChain은 DelegatingFilterProxy 대신 FilterChainProxy에 등록된다.(이 말이 정확히 무슨 의미인지 모르겠다. SecurityFilterChain이 존재하기 이전 DelegatingFilterProxy에 다른 역할이 있었는지 궁금해서 찾아봤는데 적어도 3.0버전까지는 지금과 기능상으로는 별 차이가 없다.)

 

FilterChainPrxoy는 여러 이점을 제공한다.

1. Spring Security의 모든 Servlet에 대한 entry point를 제공하므로 디버깅 혹은 servlet 설정을 간편하게 할 수 있다.

2. 메모리 누수를 피하기 위해 SecurityContext(세션)을 지우거나 HttpFirewall을 적용하여 외부의 공격으로부터 애플리케이션을 보호한다. 

3. 호출 시기 (Matchr)를 정할 때 오직 URL 기반으로만 매칭하는 것이 아닌 HttpServletRequest의 모든 정보를 기반으로 호출 시기를 결정할 수 있다.

 

FilterChain이 다수 존재하는 경우에서도 FilterChainProxy는 패턴을 찾아 결정할 수 있다.주의할 점은 SecurityFilterChain의 구성은 모두 고유하기 때문에 어떤 SecurityFilterChain에는 보안 설정이 0개일 수도, 어떤 SecurityFilterChain에는 보안 관련 설정이 5개일 수도 있다.일관적인 보안 정책 유지를 원한다면 이를 확인해야 한다.

 

 

 

 

어플리케이션 실행 시 HttpSecurityConfiguration에서 각 필터를 초기화한다.

 

 

 

 

이후 우리가 등록한 설정을 확인하며 HttpSecurityConfiguration에 반영한다.

 

 

 

 

 

빈이 모두 등록되면 FilterChainProxy가 List<SecurityFilterChain>을 인자로 받아 생성되고,

모든 구성이 완료되면 위와 같은 형태의 필터 목록을 가지게 된다.

기본 구성 필터의 순서는 아래와 같다. (레퍼런스를 그대로 캡쳐했다.)

 

 

 

 

 

 

 

 

 

 

API 요청이 전송된 이후의 흐름까지 모두 살펴보면 좋겠지만 작성할 게 너무 많아서 쓰다가 다 지워버렸다.. 오늘은 여기까지.