https://docs.spring.io/spring-security/reference/index.html
CSRF 공격이란?
Cross-Site Request Forgery
사이트 간 요청 위조의 줄임말.
웹 애플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 해서 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격 방법이다.
이는 사용자의 인증된 세션을 악용하는 공격 방식이다. 세션 로그인을 사용하고 있다면, CSRF 공격에 대한 대책이 어느정도 필요한 것 같다.
그래서 나는 Spring Security에서 제공하는 CSRF Token을 발행해 인증된 사용자의 요청을 재인증할 것이다.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
...
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors().and()
//csrf 설정
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
.authorizeHttpRequests((authz) -> authz
... )
.formLogin()
...
return http.build();
}
}
.disable()
로 설정하면 된다.일반적으로 GET
요청일 때에는 토큰을 사용하지 않는다. 그외의 POST
, DELETE
등의 요청일 때, 클라이언트 측에서는 요청 헤더에 서버로 부터 전달받은 CSRF Token을 넣어 보내야한다.
만약 요청 헤더에 토큰이 없거나 유효하지 않다면 서버는 403
오류 코드를 반환한다.
내 경우에는, 글을 작성/수정하는 요청이 POST
방식이니 글 작성/수정 폼이 있는 html 파일에 아래와 같이 추가해줬다.
<!-- csrf token -->
<meta name="_csrf" th:content="${_csrf.token}">
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
만약 타임리프의 form 요청을 사용하고 있다면 그냥 히든 인풋 태그에 토큰을 넣어 요청하면 된다.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
나는 fetch API
를 이용한 비동기 통신을 하고 있어서 전자의 방식을 따랐다.
fetch API로 요청할 때 헤더에 넣을 내용을 변수로 분리했다. 이 파일을 제일 먼저 import하면 된다.
//csrf token
const csrfHeader = document.querySelector('meta[name="_csrf_header"]').content;
const csrfToken = document.querySelector('meta[name="_csrf"]').content;
//headers 에 csrfToken 설정
//json 타입
const jsonHeaders = {
"Content-Type": "application/json",
};
jsonHeaders[csrfHeader] = csrfToken;
그리고 적용!
//fetch API
async function savePosting(url) {
const data = {
...
};
try {
const response = await fetch(url, {
method: 'POST',
//csrfHeaders
headers: jsonHeaders,
body: JSON.stringify(data)
});
//성공
if(response.status === 200) {
...
}
} catch(err) {
console.log(err);
}
}
ㄴ( ・ㅂ・)ㄱ ㄴ(・ㅂ・ )ㄱ ̑̑ 둠칫 ㄴ( ・ㅂ・)ㄱ ㄴ(・ㅂ・ )ㄱ ̑̑ 두둠칫
이런식으로 모든 요청에 적용시켜주면된다 ~0~
다음 포스팅에서는 엄청나게 헤맸던(...) multipart/form-data
타입일 경우 csrf 토큰을 어떻게 보내야하는지 알아보도록 하겠다!
몬말인지하나도모르갤다