[ 정수원 스프링 시큐리티 #1 ] 스프링 시큐리티 기본 API & Filter 이해 (8)

김수호·2024년 3월 9일
0
post-thumbnail

지난 포스팅에 이어, 이번 포스팅에서는 13) 의 내용을 정리한다.

👉 목차는 다음과 같다.

1) 인증 API - 프로젝트 구성 및 의존성 추가
2) 인증 API - 사용자 정의 보안 기능 구현
3) 인증 API - Form Login 인증
4) 인증 API - Form Login 인증 필터 : UsernamePasswordAuthenticationFilter
5) 인증 API - Logout 처리, LogoutFilter
6) 인증 API - Remember Me 인증
7) 인증 API - Remember Me 인증 필터 : RememberMeAuthenticationFilter
8) 인증 API - 익명사용자 인증 필터 : AnonymousAuthenticationFilter
9) 인증 API - 동시 세션 제어, 세션 고정 보호, 세션 정책
10) 인증 API - 세션 제어 필터 : SessionManagementFilter, ConcurrentSessionFilter
11) 인가 API - 권한 설정 및 표현식
12) 인증/인가 API - 예외 처리 및 요청 캐시 필터 : ExceptionTranslationFilter, RequestCacheAwareFilter
13) Form 인증 - 사이트 간 요청 위조 : CSRF, CsrfFilter

바로 하나씩 확인해보자.


13) Form 인증 - 사이트 간 요청 위조 : CSRF, CsrfFilter

이번 내용에서는 CSRF, CsrfFilter에 대해서 알아보자.

  • 참고)
    • 위 그림을 통해, 공격자가 있고, 사용자 그리고 쇼핑몰이 있다고 가정하자.
    • 먼저, 사용자가 쇼핑몰에 접속하여 로그인 인증을 했고, 쇼핑몰로 부터 세션쿠키를 발급받았다.
    • 이때, 공격자가 사용자 이메일로 어떤 링크를 전달한다.
    • 사용자는 링크를 클릭하고, 공격자가 만든 웹 페이지에 접속한다.
    • 그 공격용 페이지에는 로또 당첨에 대한 이미지 태그가 하나 있고, img src에는 지금 사용자가 접속한 쇼핑몰의 링크와 함께 공격자의 주소가 파라미터로 작성되어 있다.
    • 이미지를 클릭하게 되면, 브라우저는 이미지 파일을 받아오기 위해 해당 공격용 URL을 연다. 그러면 그 쇼핑몰은 사용자의 요청에 쇼핑몰이 발급한 쿠키 정보가 있으니, 해당 요청은 정상적인 요청이라고 판단하게 되고, 해당 요청에 대해서 아무런 의심없이 응답하게 된다.
    • 즉, 공격자가 심어둔 방식으로, 사용자의 의도와는 무관한 요청이 처리될 수 있다. (ex. 사용자의 승인이나 인지 없이 배송지가 등록되는 등) 이러한 취약점에 대한 공격 기법을 "사이트 간 요청 위조(CSRF)" 라 한다.

 

스프링 시큐리티는 이러한 CSRF를 방지하기 위해서 API를 제공한다.
그러면 어떤 방식으로 API를 설정하면 되는지 알아보자.

  • 참고)
    • 스프링 시큐리티는 CsrfFilter 라는 필터를 생성해서 CSRF의 취약점을 방지할 수 있도록 처리하고 있다.
    • 이 필터는 모든 요청에 대해서 랜덤하게 토큰을 생성해서 클라이언트에게 발급한다. 그 다음부터 클라이언트는 서버에 요청을 할 때, 발급받은 토큰을 보내야 한다.
    • 만약, 요청 시 전달되는 토큰 값과 서버에 저장된 실제 값을 비교한 후 일치하지 않으면 요청은 실패한다.
    • 즉, 클라이언트가 최초에 접속할 때 스프링 시큐리티는 CsrfFilter 를 통해서 클라이언트에게 CsrfToken을 발급한다. 그러면 클라이언트에서는 form 태그에 hidden 타입으로 발급된 토큰명과 토큰값을 설정할 수 있다. 이후 서버에 (PATCH, POST, PUT, DELETE) 와 같은 HTTP 메서드 방식으로 요청을 할 때는, 반드시 서버에서 발급한 토큰 정보를 가지고 요청해야 한다.
    • 참고) 스프링 시큐리티에서는 http.csrf() 가 기본으로 활성화 되어 있어서, 직접 API를 지정하지 않아도 된다. 만약, csrf 기능을 끄고 싶다면 http.csrf().disabled() 로 설정하면 된다.

 

👉 그러면 csrf 토큰 값을 가지고 POST 방식으로 요청할 때와, 그렇지 않을 때 어떻게 처리되는지 확인해보자.

  • SecurityConfig 수정
    • 스프링 시큐리티는 기본적으로 csrf 기능을 활성화해서 처리한다.
  • SecurityController 수정
    • 루트 경로 접근을 Get 방식과 Post 방식으로 두 개 작성해두었다.
  • 서버를 기동한 뒤, postman을 통해 루트 페이지를 POST 방식으로 요청해보자.
    • 참고) 토큰값을 헤더나 바디에 별도로 설정하지 않고, POST 방식으로 요청했다.
    • 요청을 해보면, CsrfFilter가 그 요청을 받고, 현재 요청에 대해서 서버에 저장된 토큰과, 사용자로부터 헤더나 파라미터 정보로 요청된 토큰 정보(actualToken)가 일치하는지 확인한다.
      • 만약, 일치하지 않은 경우 accessDeniedHandler 를 호출해서 정상적인 접근을 하지 못하도록 처리한다.
    • 결과를 보면, Forbidden 403 오류로 접근이 안되는 것을 확인할 수 있다.
  • 그러면 이번엔 CsrfFilter 에서 현재 서버에 저장된 토큰 정보를 확인해서, 헤더에 설정하고 요청해보자.
    • 참고) X-CSRF-TOKEN 는 헤더 토큰명이고, _csrf 는 파라미터로 전달할 때의 파라미터 토큰명이다.
  • 헤더에 설정 후 POST 요청 해보면, 이제 두개의 토큰 값이 서로 일치하기 때문에 csrf 검사를 통과하고, 정상적으로 자원에 접근되는 것을 확인할 수 있다.
  • SecurityConfig 수정: 이번엔 csrf 기능을 사용하지 않고 비활성화 하는 경우를 살펴보자.
    • csrf 기능을 비활성화 했다. 비활성화 하게 되면, csrf 필터는 더이상 필터 목록에서 생성되지 않는다. 따라서 해당 CsrfFilter 필터 자체를 거치지 않는다.
  • FilterChainProxy 클래스를 디버깅하여 확인해보자.
    • FilterChainProxy가 가지고 있는 필터 목록 중, CsrfFilter가 없는 것을 확인할 수 있다.
  • 실행 후 POST 방식으로 요청해보자.
    • csrf 기능을 비활성화 하면, 토큰 정보가 없어도 접근되는 것을 확인할 수 있다.
    • 참고) 운영시에는 되도록이면 csrf 기능을 활성화해서 사용해야 한다.
  • 참고) thymeleaf 같은 뷰 템플릿의 경우에는 기본적으로 post 방식으로 요청을 할 때, csrf 토큰을 파라미터로 생성해준다. 또한 스프링의 form 태그를 사용할 때에도 csrf 토큰 값을 생성해준다. 그런데 jsp를 사용하거나 일반적인 form 방식으로 할 때는, 직접 form 태그에 csrf 정보를 hidden 정보로 설정해야 한다. 그래야 정상적으로 요청이 이뤄진다.

강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 정수원 강사님께 있습니다.

profile
현실에서 한 발자국

0개의 댓글