본문 바로가기

Spring/Security

Spring Security 2: SecurityFilter #1

이번 시간에는 스프링 시큐리티의 다양한 필터들에 대해 하나씩 알아보도록 하자. 그 전에 필터와 인터셉터의 차이 먼저 짚고 넘어가자.

 

필터 - 자바의 서블릿 기반 웹 애플리케이션에서 사용된다.
즉, 서블릿 명세에 정의된 구성 요소로서 웹 애플리케이션의 요청과 응답을 가로채는 역할을 한다.

 

인터셉터 - 스프링 프레임워크에서 제공되는 기능(디스패처 서블릿이 컨트롤러로 요청을 전달하기 전후로 특정
작업을 전달하는 기능

 

필터는 요청이 들어오자마자 처음으로 거치는 단계. 스프링 컨텍스트 외부에서 작동하며 톰캣 같은 서블릿 컨테
이너 수준에서 작동

 

인터셉터는 필터를 거친 후, 스프링의 DispatcherServlet이 컨트롤러로 요청을 처리하기 전과 후에 동작

 

사실 위와 같이 설명을 했지만 스프링 버전 1.2부터 DelegatingFilterProxy를 통해 필터를 등록하고 인터셉터처럼 사용 가능하다. 따라서 규칙을 정한 후 어느정도 유연함을 챙기며 개발해도 될 듯 싶다.

 

또한 스프링 부트에서는 WAS가 내장되어 있어 DelegatingFilterProxy에 필터를 등록하지 않더라도 빈으로만 등록해주면 필터가 자동으로 적용이 된다.(스프링 프레임워크는 DelegatingFilterProxy에 필터를 등록 해줘야 동작함)

 

이는 필터와 인터셉터간의 경계를 모호하게 하는데 부트를 사용하더라도 DelegatingFilterProxy에 필터를 등록해주는 것이 필터 관리에 있어 더 낫다고 생각한다.

스프링 시큐리티 필터를 어떻게 거칠까?

앞서 필터에 대해 설명했는데 그렇다면 필터는 스프링 시큐리티의 필터는 어떻게 필터로 등록이 될까?
이야기 했듯이 어플리케이션을 실행하게되면 다양한 필터를 거치게 되는데, 이 중 DelegatingFilterProxy(자바에서 제공하는 필터의 구현체) 라는 필터를 거친다. 해당 필터는 FilterChainProxy에게 요청을 위임 하며 FilterChainProxy에 등록된 다양한 필터를 거치게 된다.

Authentication Manager - 인증 모듈

Access Decision Manager - 인가 모듈

FilterChainProxy

  • 스프링 시큐리티의 실질적인 구현은 서블릿 필터를 통해 이루어진다.
  • 서블릿 필터는 웹 요청을 가로챈 후 전처리 또는 후처리를 수행하거나 요청 자체를 리다이렉트 한다.
  • 웹 요청은 이러한 필터체인을 차례씩 통과하게 된다.
  • 웹 요청은 모든 필터를 통과하게 되지만, 모든 필터가 동작하지는 않는다.
  • 필터체인은 SpringSecurityFilterChain이라는 이름의 빈으로 등록되어 있다.
  • 필터체인은 DeligatingFilterProxy(자바에서 제공하는 필터의 구현체)를 통해 요청이 전달된다.
  • (참고)DeligatingFilterProxy는 스프링에서 제공해주는 필터고 스프링 시큐리티에서 제공해주는 필터가 아니다.

 

스프링 시큐리티에 등록되어있는 필터 6.1버전

자세히는 못보더라도 각 필터가 어떤 역할을 하는지 간단하게 알아보고 넘어가자

RequestCacheAwareFilter

  • 접근 거부를 발생시킨 원래의 페이지로 인증이후에 리다이렉션 시키기 위해서 존재하는 필터(캐시된 필터가
    있다면 요청을 올바르게 처리)
  • 익명 사용자가 보호받는 리소스에 접근할 경우 접근 거부 예외가 발생함.
  •  FilterSecurityInterceptor가 던진다.
  • 예외는 AutorizationFilter가 던진다. (스프링 시큐리티 6.1부터 바뀜) 예외를 받은 ExceptionTranslationFilter가 접근 거부 예외를 처리한다.
    -> 즉, 이 말은 ExceptionTranslationFilter에서 커스텀한 필터에서 던진 예외를 처리하게 하고 싶으면 해당 필터 아래에 위치해야 한다.(예를 들면 ExceptionTranslationFilter를 거친 뒤 커스텀 필터를 거쳐야 함)
  • (참고)모든 필터 클래스에 doFilter라는 메소드가 있으니 해당 메소드를 참고하면 더 자세한 내용을 확인 가능

 

ChannelProcessingFilter

  • http 요청을 https로 리다이렉트 시키는 필터
  • 필터 파이프라인에 아래와 같이 등록하며 된다.

 

.requiresChannel((requiresChannel) -> requiresChannel
                        .anyRequest().requiresSecure()
                )

+번외

SSL 적용(임의로 하기)
java 설치 경로에 bin 디렉토리 내에 keytools가 존재함 (이거 이용해서 만들거)

  1. keystore 만들기
    keytool -genkey -alias [keystore 별칭] -keyalg RSA -storetype PKCS12 -keystore [keystore 파일]
  2. keystore에서 인증서 추출
    keytool -export -alias [keystore 별칭] -keystore [keystore 파일] -rfc -file [인증서 파일]
  3. trust-store 만들기
    keytool -import -alias [trust keystore 별칭] -file [인증서 파일] -keystore [trust keystore 파일]
  4. ssl 인증서 적용
server:
  port: 443 
  ssl: 
    enabled: true 
    key-alias: prgrms_keystore # 별칭 
    key-store: classpath:prgrms_keystore.p12 #key-store 경로 
    key-store-password: prgrms123 # 앞서 설정한 key-store에 대한 비밀번호 
    key-password: prgrms123 # 앞서 설정한 key에 대한 비밀번호 
    trust-store: classpath:prgrms_truststore.p12 # trust-store 경로 
    trust-store-password: prgrms123 # 앞서 설정한 trust-store 비밀번호

5. 스프링 시큐리티에 requiresSecureChannel 추가

 

AnonymousAuthenticationFilter

  • 인증되지 않은 사용자에 대해 null이 아닌 Anonymous 인증 타입으로 표현하게 함.
  • 필터 파이프라인에 아래와 같이 추가하면 됨

 

.anonymous((anonymous) -> anonymous
                        .principal("thisIsAnonymousUser")
                        .authorities("ROLE_ANONYMOUS", "ROLE_UNKNOWN")
                )

추가 필터에 대한 내용은 다음장에서 설명하겠슴다~