- Spring Security 아키텍처
- Spring Security는 서블릿 기반 애플리케이션에서 서블릿 필터를 사용합니다.
- HTTP 요청이 들어오면 컨테이너는 FilterChain을 생성합니다.
- FilterChain은 요청 URI 경로를 기반으로 처리할 Filter 인스턴스들과 Servlet을 포함합니다.
- 여러 Filter가 요청을 가로채거나 수정할 수 있으며, 최종적으로 하나의 Servlet이 요청을 처리합니다.
- Filter의 순서가 매우 중요하며, 이는 보안 로직의 순서를 결정합니다.

- DelegatingFilterProxy
- 서블릿 컨테이너의 생명주기와 Spring의 ApplicationContext를 연결하는 역할을 합니다.
- 서블릿 컨테이너에 표준 방식으로 등록되지만, 실제 작업은 Spring Bean으로 등록된 Filter에 위임합니다.
- ApplicationContext에서 Bean Filter를 찾아 작업을 위임하는 방식으로 동작합니다.
- Filter Bean 인스턴스의 검색을 지연시킬 수 있어, 컨테이너 시작 시점의 문제를 해결합니다.

- FilterChainProxy
- Spring Security의 서블릿 지원을 총괄하는 특별한 Filter입니다.
- SecurityFilterChain을 통해 여러 Filter 인스턴스에 작업을 위임합니다.
- 일반적으로 DelegatingFilterProxy에 의해 감싸져 있습니다.
- Spring Security 서블릿 지원의 시작점 역할을 하며, 디버깅 시 좋은 시작점이 됩니다.
- SecurityContext 정리, HttpFirewall 적용 등 필수적인 작업을 수행합니다.

- SecurityFilterChain
- FilterChainProxy가 현재 요청에 대해 어떤 Spring Security Filter를 호출할지 결정하는 데 사용됩니다.
- 여러 SecurityFilterChain이 존재할 수 있으며, 첫 번째로 일치하는 체인만 호출됩니다.
- 각 SecurityFilterChain은 고유하며 독립적으로 구성될 수 있습니다.
- URL 패턴 외에도 HttpServletRequest의 어떤 요소로도 매칭을 결정할 수 있습니다.

- Security Filters
- 인증, 권한 부여, 취약점 방지 등 다양한 목적으로 사용되는 필터들입니다.
- 특정 순서로 실행되어 올바른 시점에 호출됩니다. 예를 들어, 인증 필터가 권한 부여 필터보다 먼저 실행됩니다.
- 필터의 순서는 FilterOrderRegistration 코드에서 확인할 수 있습니다.
- 주요 필터로는 CsrfFilter, UsernamePasswordAuthenticationFilter, BasicAuthenticationFilter, AuthorizationFilter 등이 있습니다.

- 커스텀 필터 추가
- 대부분의 경우 기본 보안 필터로 충분하지만, 때로는 커스텀 필터를 추가해야 할 수 있습니다.
- 커스텀 필터는 Filter 인터페이스를 구현하거나 OncePerRequestFilter를 상속받아 만들 수 있습니다.
- HttpSecurity의 addFilterBefore(), addFilterAfter(), addFilterAt() 메서드를 사용하여 필터 체인에 커스텀 필터를 추가할 수 있습니다.
- 필터의 위치를 신중히 선택해야 합니다. 예를 들어, 인증 후 실행되어야 하는 필터는 인증 필터 이후에 위치해야 합니다.
- 커스텀 필터를 Spring Bean으로 선언할 때는 주의가 필요합니다. 자동 등록을 피하기 위해 FilterRegistrationBean을 사용할 수 있습니다.
- 보안 예외 처리
- ExceptionTranslationFilter는 AccessDeniedException과 AuthenticationException을 적절한 HTTP 응답으로 변환합니다.
- 이 필터는 FilterChainProxy의 Security Filters 중 하나로 삽입됩니다.
- 인증되지 않은 사용자나 AuthenticationException 발생 시, 인증 프로세스를 시작합니다.
- AccessDeniedException 발생 시, AccessDeniedHandler를 호출하여 접근 거부를 처리합니다.
- 이 필터는 try-catch 블록과 유사한 방식으로 동작하여 애플리케이션의 다른 부분에서 발생한 보안 예외를 잡아 처리합니다.

- 인증 사이 요청 저장
- 인증이 필요한 리소스에 대한 미인증 요청을 저장하고, 인증 성공 후 원래 요청을 재실행하는 메커니즘입니다.
- RequestCache 인터페이스를 사용하여 HttpServletRequest를 저장하고 검색합니다.
- 기본적으로 HttpSessionRequestCache가 사용되며, 이는 HttpSession에 요청을 저장합니다.
- RequestCacheAwareFilter가 RequestCache를 사용하여 저장된 요청을 재실행합니다.
- NullRequestCache를 사용하여 이 기능을 비활성화할 수 있습니다. 이는 항상 홈 페이지로 리다이렉트하거나 요청 저장을 원치 않을 때 유용합니다.
- 로깅
- Spring Security는 모든 보안 관련 이벤트에 대해 DEBUG와 TRACE 레벨의 포괄적인 로깅을 제공합니다.
- 이는 애플리케이션 디버깅에 매우 유용합니다. 특히 Spring Security가 보안상의 이유로 응답 본문에 상세한 오류 정보를 추가하지 않기 때문에 로그가 중요합니다.
- 401(Unauthorized) 또는 403(Forbidden) 오류 발생 시, 로그 메시지를 통해 문제의 원인을 파악할 수 있습니다.
- 로깅 예시: CSRF 토큰 누락으로 인한 요청 거부 시, 로그에서 "Invalid CSRF token found for http://localhost:8080/hello"와 같은 메시지를 확인할 수 있습니다.
- 로깅 설정 방법:
- 추가적인 고려사항
- Spring Security의 구성은 매우 유연하며, 다양한 보안 요구사항을 충족시킬 수 있습니다.
- 필터의 순서와 구성을 잘 이해하고 있어야 원하는 보안 로직을 정확히 구현할 수 있습니다.
- 커스텀 필터 추가 시, 기존 Spring Security 필터들과의 상호작용을 고려해야 합니다.
- 보안 설정 변경 시 항상 철저한 테스트가 필요합니다. 작은 변경사항도 전체 보안 구조에 영향을 줄 수 있습니다.
- 로깅은 문제 해결뿐만 아니라 보안 감사에도 매우 유용하므로, 프로덕션 환경에서도 적절한 로그 레벨 설정이 중요합니다.
출처 : https://docs.spring.io/spring-security/reference/servlet/architecture.html#servlet-securityfilterchain