본문 바로가기

스프링

[Security] Spring Security Filters

Spring Security Filter

웹 애플리케이션은 Tomcat 서블릿 컨테이너에 의해 구동이 된다.

Tomcat 서블릿 컨테이너는 서블릿들을 관리해주는 역할을 하고 서블릿은 클라이언트의 요청을 처리하고 결과를 반환할 수 있도록 서블릿 클래스의 구현 규칙을 지켜 만드는 자바 웹 프로그래밍 기술이다.

서블릿에는 우리가 Spring MVC에서 사용되는 Front Controller인 DispatcherServlet이 존재하여 요청 URL에 대한 처리를 해준다.

또한, 서블릿에는 네트워크 통신의 사이 사이에서 여러 동작을 행하게 할 수 있는 클래스인 Filter가 존재한다.

이 필터들 중 DelegatingFilterProxy라는 것이 존재하고 서블릿 필터 처리를 스프링에 들어있는 빈으로 위임하고 싶을 때 사용하는 필터이다.

우리가 Spring Security를 사용하고 싶을 때, 스프링 부트에서는 자동으로 SecurityFilterAutoConfiguration을 등록하여 springSecurityFilterChain이라는 빈에 위임한다.

이는 실제로 FilterChainProxy에 위임되어 Security Filter 동작을 수행한다.

FilterChainProxy는 Security 설정 정보로부터 필요한 필터들을 가져와 SecurityFilterChain에 보관한다.

보관된 Filter들은 다음과 같다.

WebAsyncManagerIntegrationFilter

SecurityContextHolder는 ThreadLocal 방식으로 Authentication 객체를 공유할 수 있도록 도와준다.

하지만, 비동기 처리 기능을 사용한다면 다른 쓰레드를 생성하여 작업을 처리하기에 ThreadLocal 방식으로 Authentication을 공유받지 못한다.

하지만, Spring MVC의 Async 기능을 사용할 때도 Authentication 객체가 필요하면 사용할 수 있게 위의 필터를 제공한다.

SecurityContextPersistenceFilter

우리는 이전에 인증과정을 살펴봤었다.

그 때, 맨 처음 인증 받은 객체가 HTTP 세션에 저장되어있는지 확인한 후 저장이 되어 있다면 SecurityContext를 불러와 사용했고 없다면 처음부터 인증을 시작했다.

인증을 완료한 SecurityContext를 HTTP 세션에 저장하거나 SecurityContext를 HTTP 세션에서 불러오려고 할 때 이를 사용한다.

SecurityContextRepository의 구현체인 HttpSessionSecurityContextRepository를 활용하여 가져온다.

HeaderWriterFilter

응답 헤더에 Security Header를 추가해준다.

  • XContentTypeOptionsHeaderWriter - 마임 타입 스니핑 방어
  • XXSSProtectionHeaderWriter - 브라우저에 내장된 XSS 필터
  • CacheControlHeadersWriter - 캐시 히스토리 취약점 방어
  • HstsHeaderWriter - HTTPS를 활용하도록 조정
  • XFrameOptionsHeaderWriter - Click Jacking 방어

CsrfFilter

CSRF Attack을 방어하기 위한 기법을 적용한 필터이다.

Login Form에 CSRF 토큰을 포함시켜 전송할 때, CSRF 토큰을 전달받아서 기존의 토큰과 일치하는지 비교하여 성패를 결정한다.

LogoutFilter

우리가 흔히 로그아웃을 할 때 사용하는 필터이다.

LogoutHandler를 이용해 로그아웃시 필요한 처리를 진행한다.

LogoutSuccessHandler을 이용해 로그아웃 이후 필요한 처리를 진행한다.

AuthenticationFilter

인증을 처리할 때 사용되는 필터이다.

Form Login을 처리할 때 사용되는 필터는 UsernamePasswordAuthenticationFilter이다.

Form Login 처리 과정은 이전 포스트에서 확인할 수 있다.

OAuth2를 처리할 때 사용되는 필터는 OAuth2LoginAuthenticationFilter이다.

DefaultLoginPageGeneratingFilter

기본 Form Login Page를 생성해준다.

Get 요청의 Login을 처리한다.

기본으로 생성하는 것이 아니라 커스터마이징한 페이지를 로그인 페이지로 사용하는 것 또한 가능하다.

DefaultLogoutPageGeneratingFilter

기본 Form Logout Page를 생성해준다.

Get 요청의 Login을 처리한다.

기본으로 생성하는 것이 아니라 커스터마이징한 페이지를 로그아웃 페이지로 사용하는 것 또한 가능하다.

BasicAuthenticationFilter

HTTP Basic 인증을 처리하는 필터이다.

HTTP Basic이란, 요청 헤더에 BASE 64 방식으로 인코딩하여 username과 password를 실어보내 인증하는 방식이다.

보안이 취약해 HTTPS를 사용하는 것이 좋다.

RequestCacheAwareFilter

현재 요청과 관련된 요청이 캐쉬되어있는지 확인하고 있다면 적용하는 필터이다.

캐시된 것이 있다면 캐시된 것을 활용하여 처리하고 없다면 기본적인 방식을 따라 처리한다.

SecurityContextHolderAwareRequestFilter

다음의 API를 구현해준다.

  • HttpServletReqeust#authenticate(HttpServletResponse)
  • HttpServletReqeust#login(String, String)
  • HttpServletReqeust#logout()
  • AsyncContext#start(Runnable)

AnonymousAuthenticationFilter

인증받지 않은 객체에 대해 null이 아니라 익명의 객체라고 만들어주는 역할을 한다.

즉, Authentication을 Anonymous 객체로 생성하여 적용한다.

SessionManagementFilter

Session 변조 공격 방지 기능을 한다.

  • none - 아무런 전략을 사용하지 않는다.
  • newSession - 로그인을 하면 새로운 세션을 만들어서 진행한다.
  • migrateSession - 로그인을 하면 새로운 세션을 생성하고 기존 세션의 속성들을 복사하여 진행한다.
  • changeSessionId - 로그인을 하면 기존 세션의 ID만 변경하여 진행한다. (디폴트)

유효하지 않은 세션을 리다이렉트 시킬 URL을 설정한다.

  • invalidSessionUrl(Url주소)

최대 세션 수를 설정할 수 있다.

  • maximumSessions(세션수)

동시 로그인을 제어할 수 있다.

  • maxSessionsPreventsLogin(Boolean)
    • True : 이전 세션을 유지
    • False : 이전 세션 만료

세션 생성 전략을 제어할 수 있다.

  • IF_REQUIRED - 필요하면 생성한다.(디폴트)
  • NEVER - 시큐리티에서 생성하지 않는다. (기존에 세션이 있다면 사용한다.)
  • STATELESS - 세션이 존재해도 사용하지 않는다. (세션을 절대 사용하지 않으며 RESTAPI에서 사용하는 전략이다.)
  • ALWAYS - 세션을 항상 생성한다.

ExceptionTranslationFilter

인증과 인가 과정의 에러 처리를 담당하는 필터이다.

AutehnticationException은 인증 처리가 안된 사용자가 인증이 필요한 URL에 접근하면 발생하는 Exception이다.

AutehnticationEntryPoint로 이동하여 에러를 처리하고 보통 /login으로 보내 로그인을 처리한다.

  • AuthenticationEntryPoint vs AuthenticationFailureHandler
    • AuthenticationEntryPoint는 인증이 안된 사용자가 인증이 필요한 URL에 접근해야할 때 발생하는 예외를 처리한다.
    • AuthenticationFailureHandler는 로그인에 실패할 시 발생하는 예외를 처리한다.

AccessDeniedException은 인가 처리가 안된 사용자가 어떤 권한이 필요한 URL에 접근하면 발생하는 Exception이다.

기본적으로 에러 페이지를 띄우고 AcecessDeniedHandler를 오버라이드하여 커스터마이징할 수 있다.

FilterSecurityInterceptor

AccessDecisionManager를 사용하여 인가를 처리한다.

authorizeRequests()에 대한 세팅값이다.

RememberMeAuthenticationFilter

로그아웃을 하거나 브라우저를 끄면 세션이 만료되어 추후에 다시 로그인하여 인증 요청을 해야한다.

Remember을 사용하여 구현하게 되면 세션이 만료되어도 쿠키 또는 DB를 사용하여 저장된 토큰 기반으로 인증을 진행할 수 있도록 한다.

이 때 사용하는 필터이다.