[Spring Security] CSRF 방어

식빵·2022년 8월 14일
0
post-thumbnail

이 시리즈에 나오는 모든 내용은 인프런 인터넷 강의 - 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 에서 기반된 것입니다. 그리고 여기서 인용되는 PPT 이미지 또한 모두 해당 강의에서 가져왔음을 알립니다.


🥝 CSRF 공격 방식

위와 같은 일을 방지하기 위해서 요청시에 서버에서 랜덤하게 만든 CSRF 토큰 값을
같이 보내도록 하는 것이 바로 CSRF 방어다.

요청으로 온 CSRF 토큰을 현재 서버에 저장된 CSRF 토큰의 값을 비교해서 일치하면
정상적으로 처리가 되고, 아니면 예외를 터뜨리게 된다.



🥝 CSRF 토큰 보내는 방법

  • FORM INPUT 으로 보내기
    • <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    • 지원하는 HTTP METHOD: PATCH, POST, PUT, DELETE
  • HTTP HEADER 로 보내기
    • HEADER 에 X-CSRF-TOKEN 추가

참고로 우리가 아무런 설정을 안해도 스프링 시큐리티는 기본으로 Csrf 기능이 활성화
되어 있어서 CsrfFilter 가 적용된다.


🥝 CsrfFilter 코드 관찰


1번 과정
일단 CSRF 인증 검토를 위한 요청인지 아닌지를 묻지 말고,
CSRF 토큰이 현재 서버에 없다면 생성하고 나서 request 에 CSRF 토큰을 넣어서
Client 에게 전송한다.


2번 과정
여기서는 현재 요청이 POST, PATCH, PUT, DELETE 인지를 확인한다.
이를 처리하는 RequestMatcher 구현체는 아래와 같다. 참고하길.

아무튼 RequestMatcher 에 부합하는 요청이 아니라면 그냥 다음 filter 로 요청을 위임한다.


3번 과정

2번 과정에서 RequestMatcher 에 의해서 CSRF 방어가 필요한 요청이라고 판단되면
CSRF 토큰값을 요청에서 추출해낸다.

이때 추출하는 지점이 2군데이다.

  • HTTP HEADER
  • HTTP PARAMETER

그렇다면 대체 이름의 헤더, 또는 어떤 이름의 파라미터를 읽어오는 것일까?
그건 HttpSessionCsrfTokenRepository 에서 확인할 수 있다.

  • 파라미터 방식일 경우: _csrf
  • HEADER 방식일 경우: X-XSRF-TOKEN

아무튼 이 이름의 헤더 또는 파라미터에서 값을 뽑아내고
그 값을 현재 서버의 토큰값과 비교하게 된다.

그리고 비교 결과 뭔가 맞지 않다면 accessDeniedHandler 를 호출한다.




🥝 CsrfFilter 테스트

0. 스프링 시큐리티 설정


@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    
        http
            .authorizeRequests()
            .anyRequest().permitAll(); // permitAll 로 설정!
    
        http.formLogin();
        
    }
}



1. Controller 메소드 추가

@PostMapping("/")
public String postIndex() {
    return "postHome";
}



2. Postman 실행 및 요청


3. 요청 튕김 확인

내부적으로 AccessDeniedHandler 가 호출된다. 여기서 response.sendError 를 호출하여
Server 자체적인 에러 페이지를 호출하도록 하고 있다.



4. HEADER 에 CSRF 토큰 세팅 후 재요청

  • HEADER 에서 X-CSRF-TOKEN 설정.
  • 토큰 값은 아까 요청할 때 디버깅 포인트를 잡아서 가져옴.

5. 성공

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글