이 시리즈에 나오는 모든 내용은 인프런 인터넷 강의 - 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 에서 기반된 것입니다. 그리고 여기서 인용되는 PPT 이미지 또한 모두 해당 강의에서 가져왔음을 알립니다.
위와 같은 일을 방지하기 위해서 요청시에 서버에서 랜덤하게 만든 CSRF 토큰 값을
같이 보내도록 하는 것이 바로 CSRF 방어다.
요청으로 온 CSRF 토큰을 현재 서버에 저장된 CSRF 토큰의 값을 비교해서 일치하면
정상적으로 처리가 되고, 아니면 예외를 터뜨리게 된다.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
X-CSRF-TOKEN
추가참고로 우리가 아무런 설정을 안해도 스프링 시큐리티는 기본으로 Csrf 기능이 활성화
되어 있어서 CsrfFilter 가 적용된다.
1번 과정
일단 CSRF 인증 검토를 위한 요청인지 아닌지를 묻지 말고,
CSRF 토큰이 현재 서버에 없다면 생성하고 나서 request 에 CSRF 토큰을 넣어서
Client 에게 전송한다.
2번 과정
여기서는 현재 요청이 POST, PATCH, PUT, DELETE 인지를 확인한다.
이를 처리하는 RequestMatcher 구현체는 아래와 같다. 참고하길.
아무튼 RequestMatcher 에 부합하는 요청이 아니라면 그냥 다음 filter 로 요청을 위임한다.
3번 과정
2번 과정에서 RequestMatcher
에 의해서 CSRF 방어가 필요한 요청이라고 판단되면
CSRF 토큰값을 요청에서 추출해낸다.
이때 추출하는 지점이 2군데이다.
그렇다면 대체 이름의 헤더, 또는 어떤 이름의 파라미터를 읽어오는 것일까?
그건 HttpSessionCsrfTokenRepository
에서 확인할 수 있다.
_csrf
X-XSRF-TOKEN
아무튼 이 이름의 헤더 또는 파라미터에서 값을 뽑아내고
그 값을 현재 서버의 토큰값과 비교하게 된다.
그리고 비교 결과 뭔가 맞지 않다면 accessDeniedHandler
를 호출한다.
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 토큰 세팅 후 재요청
X-CSRF-TOKEN
설정. 5. 성공