Home Security Filter
Post
Cancel

Security Filter

서블릿 컨테이너

  • 톰켓과 같은 웹 애플리케이션을 서블릿 컨테이너라고 부른다.
  • 서블릿 컨테이너는 Filter와 Servlet로 구성되어 있다.
  • 클라이언트로부터 요청이 threadlocal로 실행되어 들어오면 각 filter들을 차례대로 거친 후 dispatchServlet이 url에따라 실행될 메소드를 찾아 Controller, Method까지 request, resonse를 넘기게된다.

filter

  • 필터는 체인처럼 엮여있기 때문에 필터 체인이라고도 불리는데, 모든 Request는 이 필터 체인을 반드시 거쳐야 서블릿 서비스에 도착할 수 있다.

SecurityFilterChain

  • filter는 모든 request에 대해서 공통적으로 적용 된다. 하지만 Security는 여러가지 정책이 공존 할 수 있다.
    • /api/test 하위의 요청들에 대한 보안 정책
    • /admin 하위의 요청들에 대한 보안 정책
  • 위의 예시처럼 경우에 따라 각각에 맞는 Security를 적용해야 하기 때문에 필터체인에 통째로 들어갈 수 없다.
    • Spring에서는 이런 문제를 해결하기 위해 DelegatingFilterProxy라는 필터를 만들어 메인 필터체인에 추가하고, 해당 Proxy밑에 다시 SecurityFilterChain그룹을 등록한다.

SecurityFilterChain

  • Proxy를 통해 filter를 선택하게 한다.
    • /api/ 로 들어오는 요청은 위의 Filter를 통과하고
    • / 로 들어오는 요청은 아래의 Filter를 통과하게한다.
  • WebSecurityConfigurerAdapter가 필터 체인을 구성하는 Configuration Class이다.
  • web resource의 경우 필터를 무시하고 통과시켜주기도 한다.

Spring Security의 Filter

  • FilterChain설정은 WebSecurityConfigurerAdapter를 상속해 설정할 수 있다.
  • Spring Security는 다양한 기본 Filter들을 제공한다.
  • SecuritContextPersistenceFilter : SecurityContextRepository에서 SecurityContext를 로드하고 저장하는 일을 담당한다.
  • HeaderWriterFilter : Http 헤더를 검사한다.
  • CorsFilter : 허가된 사이트나 클라이언트의 요청인지 확인한다.
  • CsrfFilter: CSRF attack을 방어하기 위한 Filter (post,put 처럼 서버의 리소스를 변경하는 요청에 대해서 내가 내려보낸 리소스에서 올라온 요청인지 체크한다.)
  • LogoutFilter : 로그아웃 URL로 지정된 가상 URL에 대한 요청을 감시하고 매칭되는 요청이 있다면 사용자를 로그아웃 시킨다.
  • UsernamePasswordAuthenticationFilter : username / password로 이루어진 폼기반 인증에 사용하는 가상 URL 요청을 감시하고 있으며 요청이 들어오면 사용자의 인증을 진행한다.
  • ConcurrentSessionFilter : 매 요청마다 현재 사용자의 세션 만료 여부를 체크한다.
  • BearerTokenAuthenticationFilter : Authorization 헤더에 Bearer 토큰이 있을 경우 인증 처리
  • BasicAuthenticationFilter : HTTP 기본 인증 헤더를 감시하고 처리한다.
  • RequestCacheAwareFilter : 로그인 성공 후 인증 요청에 의해 가로채어진 사용자의 원래요청을 재구성 하는데 사용된다. (로그인 페이지 이동 -> 로그인 완료 -> 목적 페이지로 이동)
  • SecurityContextHolderAwareRequestFilter : Security관련 Servlet API를 지원해준다.
  • RememberMeAuthenticationFilter : 세션이 사라지거나 만료가 되어도 쿠키/DB를 사용해 저장된 토큰 기반으로 인증을 처리한다.
  • AnonymousAuthenticationFilter : 인증을 하지 않은 요청일 경우 SecurityContextHolder에 익명 Authentication객체를 넣어준다.
  • ExcpetionTranslationFilter : 해당 Filter 이후에 인증이나 권한 예외가 발생하면 처리
  • FilterSecurityInterceptor : 기본적으로 등록되는 시큐리티 필터의 마지막 필터로 이전까지의 Filter들을 통해 발행된 Authentication을 통해 접근하려하는 URL에 권한이 있는지 체크한다.
  • DefaultLoginPageGeneratingFilter : 폼기반 인증에 사용하는 URL요청을 감시하고 있으며 폼 로그인에 필요한 HTML을 생성한다.
  • 필터는 넣거나 뺄 수 있고 순서를 조절할 수 있다.
  • 필터의 순서가 매우 critical 할 수 있기 때문에 기본 필터들은 그 순서가 어느정도 정해져 있다.

Request가 거친 Filter확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser(User.builder()
                    .username("user2")
                    .password(passwordEncoder().encode("2222"))
                    .roles("USER"))
                .withUser(User.builder()
                    .username("admin")
                    .password(passwordEncoder().encode("3333"))
                    .roles("ADMIN"));
    }

    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((requests) ->
                requests.antMatchers("/").permitAll()
                        .anyRequest().authenticated());
        http.formLogin();
        http.httpBasic();
    }
}
  • EnableWebSecurity에서 debug를 true로 하면 Request가 어떤 filter chain을 거쳤는지 Console에서 볼 수 있다.

    filterChain

  • filter disable

    1
    2
    3
    4
    5
    6
    7
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.headers().disable()
              .csrf().disable()
              .logout().disable()
              .requestCache().disable();
      }
    

    FilterChainDisable

    ### 여러개의 filter Chain구성

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
      @EnableWebSecurity
      @EnableGlobalMethodSecurity(prePostEnabled = true)
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
        
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth.inMemoryAuthentication()
                      .withUser(User.builder()
                          .username("user2")
                          .password(passwordEncoder().encode("2222"))
                          .roles("USER"))
                      .withUser(User.builder()
                          .username("admin")
                          .password(passwordEncoder().encode("3333"))
                          .roles("ADMIN"));
          }
        
          @Bean
          PasswordEncoder passwordEncoder(){
              return new BCryptPasswordEncoder();
          }
        
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http.antMatcher("/api/**/");
              http.authorizeHttpRequests((requests) ->
                      requests.antMatchers("/").permitAll()
                              .anyRequest().authenticated());
              http.formLogin();
              http.httpBasic();
          }
      }
    
    • antMatcher를 통해 해당 filter chain이 /app/ 로 들어오는 요청에만 작동되게 할 수 있다. 만약 여러개의 Filter chain을 추가하고 싶다면 Class를 추가로 만들면 된다.
      • 여러개의 필터체인을 구성할 때 순서가 중요하다. 그렇기 때문에 여러개의 필터 체인을 구성할 때에는 order를 설정해줘야한다.

        1
        2
        3
        4
        5
        6
        7
        8
        
          @Order(1)
          @EnableWebSecurity(debug = true)
          @EnableGlobalMethodSecurity(prePostEnabled = true)
          public class SecurityConfig extends WebSecurityConfigurerAdapter {
                    
            .....
          	.....
          }
        
This post is licensed under CC BY 4.0 by the author.