티스토리 뷰

Spring

Spring Boot CSRF AJAX 전송 방법

현오쓰 2019. 8. 19. 13:16

CSRF

 

CSRF ? 

사이트 간 요청 위조(또는 크로스 사이트 요청 위조, 영어: Cross-site request forgery, CSRF, XSRF)는 웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격을 말한다.  (참고 위키백과)

 

Spring Security를 사용하게 되면 FROM 혹은 AJAX로 값을 Controller에 넘길때 CSRF 토큰 값 HTTP Header에 같이 넘기면 된다.  

 

FROM으로 넘길때는 폼 태그를 사용하거나, Thymeleaf 2.1, @EnableWebSecurity를 사용하는 경우
CsrfRequestDataValueProcessor가 적용되어 from 에 CSRF 토큰이 자동적으로 들어간다.

즉, FORM으로 데이터를 보내면 위와 같은 환경이라면 CSRF 토큰값이 자동으로 들어가 따로 코드를 

작성할 필요가 없다는 말씀!...

 

하지만... AJAX는 토큰값을 헤더에 보내줘야한다! 코드와 함께 설명 가겠습니다.

 

CSRF AJAX 사용시 설정및 실행

 

haed 태그 사이에 아래와 같은 코드를 넣어줍니다.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
<title>CSRF TEST</title>
</head>

 

HTML Body 안에 들어갈 내용입니다. input 안에있는 userName을 ajax로 보낼 예정입니다.

<!--AJAX Submit-->
<div class="panel-heading"></div>
<input autocomplete="off" type="text" class="form-control" id="userName" name="name">
<button class="btn btn-md btn-danger btn-block" id="ajaxCall" type="button">AJAX Call</button> 

 

AJAX를 구현 해보겠습니다. 

meta 태그 안에있는 content를 가져와서 AJAX  beforeSend(데이터를 전송하기전) 에 HTTP Header를 

SET 해줍니다.

<script type="text/javascript">

	$(function() {
		$("#ajaxCall").click(function(){
			ajaxCall();
		});
	});
	
	function ajaxCall(){
		var token = $("meta[name='_csrf']").attr("content");
		var header = $("meta[name='_csrf_header']").attr("content");
		var name = $("#userName").val();
		
		var jsonData = {
			"name" : name
		}
		
		$.ajax({
			type: 'POST',
			contentType: "application/json",
			url:'/csrf/ajax',
			data: JSON.stringify(jsonData), // String -> json 형태로 변환
			beforeSend : function(xhr)
            {   /*데이터를 전송하기 전에 헤더에 csrf값을 설정한다*/
				xhr.setRequestHeader(header, token);
            },
			dataType: 'json', // success 시 받아올 데이터 형
			async: true, //동기, 비동기 여부
			cache :false, // 캐시 여부
			success: function(data){
				console.log(data.name);
			},
			error:function(xhr,status,error){
				console.log('error:'+error);
			}
		});
	}
	
</script>

 

컨트롤러와 VO객체

AJAX로 받아온 컨트롤러에는 CSRF 관련 소스를 작성할 필요가 없습니다.

시큐리티가 내부적으로 다 해줍니다.

 

일반적인 AJAX 호출과 동일 합니다.

@PostMapping("/csrf/ajax")
public @ResponseBody CsrfVO csrfAJAXSubmit(@RequestBody CsrfVO csrfVO) {
		
	return csrfVO;
}

 

VO객체는 아래와같으며, Lombok을 사용해 자동으로 Getter와 Setter를 만들어 주었습니다.

package com.example.demo.vo;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class CsrfVO {

	private String name;
}

 

끝입니다.. 참쉽죠잉?? 결론은 AJAX호출시 토큰값을 헤더에 잘 넘겨주면됩니다.

FORM전송은 알아서 토큰값이 들어가 있습니다.

 

CSRF를 사용하기 싫다면!!  Secutity를 설정한 Config 클래스에서 아래 코드와 같이 설정해주시면 됩니다.

.and().csrf().disable()

 

혹은 특정 URL은 CSRF 토큰 없이 프로세스를 진행 시키려면 아래와 같은 코드를 같은 Config 클래스에서 설정하시면 됩니다. 

.csrf().ignoringAntMatchers("/user/save")

 

이상입니다. ㅎㅎ 더욱 자세한 설정을 보고 싶다면 아래 URL를 참고하시길 바랍니다.

 

https://docs.spring.io/spring-security/site/docs/5.1.5.RELEASE/reference/htmlsingle/#csrf

 

Spring Security Reference

The authenticator is also responsible for retrieving any required user attributes. This is because the permissions on the attributes may depend on the type of authentication being used. For example, if binding as the user, it may be necessary to read them

docs.spring.io