Spring

Spring Security 내부 필터

꿀승 2024. 10. 24. 16:00
728x90
반응형
SMALL

  1. DisableEncodeUrlFilter

    • DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 가장 첫 번째에 위치한다.
    • 필터가 등록되는 목적은 URL 파라미터에 세션 id가 인코딩되어 로그로 유출되는 것을 방지하기 위함이다.
      //비활성화 방법
      http
              .sessionManagement((manage) -> manage.disable());
  2. WebAsyncManagerIntegrationFilter

    • DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 가장 첫 번째에 위치한다.
    • SecurityContextHolder가 ThreadLocal 전략을 사용하여 동일한 쓰레드에서만 사용하는데
      서블릿단에서 비동기 작업을 할 때 위 필터로 동일한 SecurityContextHolder를 사용 할 수 있도록 처리
  3. SecurityContextHolderFilter

    • DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 가장 세 번째에 위치한다.

    • 이전 요청을 통해 인증 된 사용자는 서버의 세션에다가 등록하여 SecurityContextHolder에 초기화 하여 인가 작업이 수행 할수 있도록 처리 → 응답 후에 SecurityContext 초기화

    • 동작흐름

      • 요청이 들어오면 서버의 세션 (메모리,redis,http 등) SecurityContextRepository 인터페이스에 loadDefferdContext()라는 메서드로 해당 유저정보를 불러온다.
      • 해당 값을 저장하고, 저장한 정보를 SecurityContextHolder에 setDefferdContext() 메소드를 통해 저장하고 다음 필터로 넘긴다.
        • SecurityContextRepository에서 정보를 불러올 때 없으면 빈 객체를 저장
      • 이후 응답이 이루어지면 try의 finally 구문을 통해 SecurityContextHolder에 유저 정보를 제거한다.
    • SecurityContextRepository 구현체

      • HttpSessionSecurityContextRepository : 서버 세션 기반 구현체
      • NullSecurityContextRepository : 아무 작업을 하지 않을때 (JWT를 사용해서 STATELESS 관리시)
      • RequestAttributeSecurityContextRepository : HTTP request 저장 기반 구현체
      • 기타 : 직접 구현해서 사용하면 된다.
    • 커스텀 등록 방법

      @Bean
      public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
      
          http
                  .securityContext((context) -> context
                          .securityContextRepository(new RequestAttributeSecurityContextRepository()));
      
          return http.build();
      }
  4. HeaderWriterFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 네 번째에 위치한다.

    • http응답헤더에 사용자 보호를 위한 시큐리티 관련 헤더추가

      //비활성화 방법
      http
              .headers((headers) -> headers.disable());
    • 필터 적용후 응답헤더 목록

      헤더
      X-Content-Type-Options 컨텐츠 스니핑을 막기 위해 nosniff value를 할당해 서버에서 응답하는 Content-Type과 다른 타입일 경우 읽지 못하도록 설정
      X-XSS-Protection XSS 공격 감지시 로딩 금지 (0은 비활성화)
      Cache-Control 이전에 받았던 데이터와 현재 보낼 데이터가 같다면 로딩에 대한 결정 여부
      Pragma HTTP/1.0 방식에서 사용하던 Cache-Control
      Expires 서버에서 보낼 데이터를 브라우저에서 캐싱할 시간
      X-Frame-Options 브라우저가 응답 데이터를 iframe, frame, embed, object 태그에서 로딩해도 되는 여부
    • 커스텀 방법

      http
              .headers((headers) -> headers
                              .frameOptions(frameOptions -> frameOptions.sameOrigin())
                              .cacheControl(cache -> cache.disable())
                              .contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
              );
  5. CorsFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 다섯 번째에 위치한다.

    • Cors (Cross-Origin Resource)는 한 도메인에서 실행되는 웹 애플리케이션이 다른 도메인에서 제공하는 리소스에 접근할 수 있게 허용하는 메커니즘입니다. 이는 보안상의 이유로 브라우저에서 기본적으로 금지되어 있기 때문에 필요합니다.

    • CorsConfigurationSource 설정 값을 설정한 값에 따라 필터단에서 응답 헤더를 설정하는 필터이다

      • CorsConfigurationSource 설정방법

        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        
            http
                .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {
        
                    @Override
                    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
        
                        CorsConfiguration configuration = new CorsConfiguration();
        
                        //요청
                        //허용할 URL 지정
                         configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
                        //허용할 Method 지정
                        configuration.setAllowedMethods(Collections.singletonList("*"));
                        //인증, 인가를 위한 credentials 를 TRUE로 설정
                        //자격 증명(쿠키, 인증 헤더 등)을 포함한 요청을 허용할지 여부를 설정합니다.
                        configuration.setAllowCredentials(true);
                        //허용할 Header 지정
                        configuration.setAllowedHeaders(Collections.singletonList("*"));
                        //캐시
                        configuration.setMaxAge(3600L);
        
                        //응답
                        configuration.setExposedHeaders(Collections.singletonList("Set-Cookie"));
                        configuration.setExposedHeaders(Collections.singletonList("Authorization"));
        
                        return configuration;
                    }
              }));
        
          return http.build();
        }
      • MVC 사용시 cors 설정을 추가 설정 필요

        @Configuration
        public class WebMvcConfig implements WebMvcConfigurer {
        
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("https://example.com")
                        .allowedMethods("GET", "POST", "PUT", "DELETE")
                        .allowedHeaders("*")
                        .allowCredentials(true)
                        .maxAge(3600);
            }
        }
    • Spring MVC 설정: Spring MVC 설정은 애플리케이션의 컨트롤러 레벨에서 들어오는 CORS 요청을 처리합니다.

    • Spring Security 설정: Spring Security 설정은 보안 필터 체인 단계에서 들어오는 CORS 요청을 처리합니다. 보안 필터 체인은 MVC 설정 전에 실행되기 때문에, 만약 보안 설정에서 CORS 처리를 하지 않으면 요청이 보안 필터 체인에서 차단될 수 있습니다.

  6. CsrfFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 여섯 번째에 위치한다.

    • 사용자의 의지와 무관하게 해커가 강제로 사용자의 브라우저를 통해 서버측으로 특정한 요청을 보내도록 공격하는 방법이다.

    • CSRF 공격 방어를 위해 HTTP 메소드 중 GET, HEAD, TRACE, OPTIONS 메소드를 제외한 요청에 대해서 검증을 진행한다.

    • CSRF 검증 방식은 토큰 방식이며 요청시 토큰을 서버 저장소에 저장 후 클라이언트에게도 전송하며, 그 후 해당하는 요청에 대해서 서버에 저장된 토큰과 비교 검증을 진행한다.

    • REST API에서는 STATELESS 를 사용하기에 사용 할 일이 거의 없음 disable

      http
              .csrf((csrf) -> csrf.disable());
      
  7. LogoutFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 일곱 번째에 위치한다.
    • 인증 후 생성되는 사용자 식별 정보에 대해 로그아웃 핸들러를 실행하여 로그아웃을 수행
    • LogoutFilter는 세션 무효화, 인증토큰 삭제 등 Security Context에서 해당 인증 객체를 삭제한다.
    • 기본적으로 세션방식에 대해 설정되어 있으므로 JWT방식이나 추가할 로직이 필요
    • 기본 제공 핸들러
      • SecurityContextLogoutHandler : SecurityContextHolder에 존재하는 SecurityContext 초기화
      • CookieClearingLogoutHandler : SecurityFilterChain의 logout 메소드에서 지정한 쿠키 삭제
      • HeaderWriterLogoutHandler : 클라이언트에게 반환될 헤더 조작
      • LogoutSuccessEventPublishingLogoutHandler : 로그아웃 성공 후 특정 이벤트 실행
    • 커스텀 로그아웃핸들러 추가
      CookieClearingLogoutHandler cookies = new CookieClearingLogoutHandler("our-custom-cookie");
      http
              .logout((logout) -> logout.addLogoutHandler(cookies));
  8. UsernamePasswordAuthenticationFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 여덟 번째에 위치한다.

    • POST : “/login” 경로에서 Form 기반 인증을 진행할 수 있도록 multipart/form-data 형태의 username/password 데이터를 받아 인증 클래스에게 값을 넘겨주는 역할을 수행한다.

    • Json이나 다른 데이터 방식으로 받을려면 수정이 필요

    • 커스텀 SecurityFilterChain을 생성하면 자동등록이 안되기에 추가 필요

      http
              .formLogin(Customizer.withDefaults());
      
    • UsernamePasswordAuthenticationFilter에는 doFilter가 존재하지 않고
      부모 클래스인 AbstractAuthenticationProcessingFilter 추상 클래스에 존재함

    • 사용자에게 데이터를 받아 인증 → 인증 결과 → 성공/실패 핸들 이러한 로직이 AbstractAuthenticationProcessingFilter 클래스에 정의되어 있고 데이터를 받는 로직이 Form경우 UsernamePasswordAuthenticationFilter 를 사용

      • attemptAuthentication 추상메서드
        public abstract Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException;
      • AbstractAuthenticationProcessingFilter doFilter안에 attemptAuthentication() 추상메소드가 존재 데이터를 받아 인증할 항목에 따라 구현
      • AbstractAuthenticationProcessingFilter 추상 클래스를 상속받아 구현된 클래스
        • UsernamePasswordAuthenticationFilter
        • OAuth2LoginAuthenticationFilter
        • Saml2WebSsoAuthenticationFilter
        • CasAuthenticationFilter
  9. DefaultLoginPageGeneratingFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 아홉 번째에 위치한다.
    • GET : “/login” 경로에 기본 로그인 페이지를 응답하는 역할을 수행한다.
    • 주로 커스텀 로그인페이지를 사용하기에 잘 사용이 안됨
    • 커스텀 SecurityFilterChain을 생성하면 자동등록이 안됨
      // 기본 사용 폼로그인 사용시에 활성화
      http
              .formLogin(Customizer.withDefaults());
      //        .oauth2Login(Customizer.withDefaults());
      // 커스텀 하더라도 아래와 같이 loginPage() 메소드를 다루지 않으면 기본 로그인 페이지 활성
      // 변경하면 기본 로그인 페이지 비활성화 처리
      http
              .formLogin((login) -> login.loginPage("/커스텀경로"));
              //.oauth2Login((login) -> oauth2Login.loginPage("/커스텀경로"));
    • 로그인 설정에 따른 활성화
      • form 로그인 (formLogin)
      • oauth2 로그인 (oauth2Login)
      • saml2 로그인 (saml2Login)
  10. DefaultLogoutPageGeneratingFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 열 번째에 위치한다.
    • GET : “/logout” 경로에 대해 기본 로그아웃 페이지를 응답하는 역할을 수행한다.
    • 주로 커스텀 로그인페이지를 사용하기에 잘 사용이 안됨
    • 커스텀 SecurityFilterChain을 생성하면 자동등록이 안됨
      // 기본 사용 방법
      http
             .formLogin(Customizer.withDefaults());
             //        .oauth2Login(Customizer.withDefaults());
  11. BasicAuthenticationFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 열한 번째에 위치한다.
    • 커스텀 SecurityFilterChain을 생성하면 자동 등록이 안되기 때문에 아래 구문을 통해서 필터를 활성화시켜/야 한다.
    • //기본 배이직인증 활성화 http .httpBasic(Customizer.withDefaults());
    • Basic 인증
      username/password를 입력하면 브라우저가 Base64로 인코딩하여 Authorization 헤더에 넣어서 전송 → 서버는 요청에 대해서 확인 후 사용자를 기억하지 않기 때문에 매 요청시 Authorization 헤더가 요구된다.
      • 요청 형식
      • Authorization: Basic BASE64로인코딩한usernamepassword값
    • → 스프링 시큐리티의 Basic 인증 로직은 매번 재인증을 요구하는 것이 아닌 세션에 값을 저장해서 유저를 기억
  12. RequestCacheAwareFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 열두 번째에 위치한다.
    • 이전 HTTP 요청에서 처리할 작업이 있고 현재 요청에서 그 작업을 수행하기 위해 등록된다.
      • 예시) 특정 경로에 접근 할 때 로그인이 권한이 필요한데 없을 경우 권한없음 예외가 발생 하고 핸들러에서 해당 경로를 기억 후 로그인 과정을 진행 후에 해당 필터에 저장되어있는 경로를 가져와 실행
  13. SecurityContextHolderAwareRequestFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 열세 번째에 위치한다.
    • ServletRequest 요청에 스프링 시큐리티 API를 다룰 수 있는 메소드를 추가하기 위함
    • API 메서드
      • authenticate() : 사용자가 인증 여부를 확인하는 메소드
      • login() : 사용자가 AuthenticationManager를 활용하여 인증을 진행하는 메소드
      • logout() : 사용자가 로그아웃 핸들러를 호출할 수 있는 메소드
      • AsyncContext.start() : Callable를 사용하여 비동기 처리를 진행할 때 SecurityContext를 복사하도록 설정하는 메소드
  14. AnonymousAuthenticationFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 열네 번째에 위치한다.
    • 여러 필터를 거치면서 현재 지점 까지 SecurityContext값이 null 인 경우 Anonymous (익명)값을 넣어주기 위해 사용
      → Anonymous로 값으로 들어가면 username : AnonymousUser, role: ROLE_ANONYMOUS
  15. ExceptionTranslationFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 열다섯 번째에 위치한다.
    • 이 필터 이후에 발생하는 인증,인가 예외를 핸들링 하기 위해 사용됨.
  16. AuthorizationFilter

    • 이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 마지막에 위치한다.
    • SecurityFilterChain의 authorizeHttpRequests()를 통해 인가 작업을 진행한 값에 따라 최종적으로 인가를 수행
    • 기본적인 인가 설정 방법
      http
             .authorizeHttpRequests((auth) -> auth
                     .requestMatchers("/").permitAll()
                     .anyRequest().permitAll());

참고

https://www.youtube.com/@xxxjjhhh - 개발자유미

728x90
반응형
LIST

'Spring' 카테고리의 다른 글

Flyway  (1) 2025.01.02
Undertow  (1) 2025.01.02
Spring Security 내부 흐름  (0) 2024.10.22
Querydsl 기본 사용법  (2) 2024.09.30
Spring Data JPA  (1) 2024.09.30