CSRF
Cross-Site Request Forgery는 요청을 위조하여 사용자가 원하지 않아도 서버측으로 특정 요청을 강제로 보내는 방식이다. ( 회원 정보 변경, 게시글 CRUD를 사용자 모르게 요청 )
package com.example.testsecurity.config;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.csrf((auth) -> auth.disable());
return http.build();
}
}
scurity config 클래스에서 csrf.disable()
설정을 진행하지 않으면 자동으로 enable 설정이 진행된다. enable 설정 시 스프링 시큐리티는 CSRFFilter
를 통해 POST
, PUT
, DELETE
요청에 대해서 토큰 검증을 진행한다.
<form action="/loginReceiver" method="post" name="loginForm">
<input type="text" name="username" placeholder="아이디"/>
<input type="password" name="password" placeholder="비밀번호"/>
<!-- 다음과 같이 csrf 토큰을 담아서 요청을 전달해야한다.-->
<input type="hidden" name="_csrf" value="{{_csrf.token}}"/>
<input type="submit" value="로그인"/>
</form>
<!-- 다음과 같이 <head>구획 아래에 요소를 추가해야한다. -->
<meta name="_csrf" content="{{_csrf.token}}"/>
<meta name="_csrf_header" content="{{_csrf.headerName}}"/>
GET 방식 로그아웃을 진행할 경우 설정 방법
csrf 설정 시 POST 요청으로 로그아웃을 진행해야 하지만 아래 방식을 통해 GET 방식으로 진행할 수 있다.
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
http
.logout((auth) -> auth.logoutUrl("/logout")
.logoutSuccessUrl("/"));
return http.build();
}
@Controller
public class logoutController {
@GetMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null) {
new SecurityContextLogoutHandler().logout(request, response, authentication);
}
return "redirect:/";
}
}
mustache에서 csrf 토큰 변수 오류 발생 시 아래 구문을 변수 설정 파일에 추가
# request 속성 추가
spring.mustache.servlet.expose-request-attributes=true
앱에서 사용하는 API 서버의 경우 보통 세션을 STATELESS로 관리하기 때문에 스프링 시큐리티 csrf enable 설정을 진행하지 않아도 된다.