본문 바로가기

프로그래밍/Spring & MyBatis

[Spring Framework] Spring Security CSRF 적용

폼 전송시 아래를 반드시 추가할 것.

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">


상단에 스프링 시큐리티 taglib를 추가하고

<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>


<sec:csrfInput /> 를 이용하여도 된다.



security-context.xml 에서 아래와 같이 csrf를 설정하면 되며

 <!-- csrf off security 4.0 over 만약 csrf를 on하면 로그아웃 부분을 post 요청으로 변경해야됨.--> <csrf disabled="false"/>


<!-- 

csrf request-matcher를 이용하면 CSRF Token을 사용하지 않도록 설정할 수 있다.

 -->

<csrf request-matcher-ref="csrfSecurityRequestMatcher"/>

<beans:bean id="csrfSecurityRequestMatcher" class="com.bellsoft.exchange.custom.authentication.CsrfSecurityRequestMatcher"/>




package com.bellsoft.exchange.custom.authentication;

import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.web.util.matcher.OrRequestMatcher;

import org.springframework.security.web.util.matcher.RegexRequestMatcher;

import org.springframework.security.web.util.matcher.RequestMatcher;

import org.springframework.stereotype.Service;

@Service("csrfSecurityRequestMatcher")

public class CsrfSecurityRequestMatcher implements RequestMatcher {

private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");

// null == match ALL HTTP methods

// true == case insensitive matching

private RequestMatcher hessianMatcher = new RegexRequestMatcher("/remote/secure/client-cert/hessian/.*", null, true);

private RequestMatcher wsMatcher = new RegexRequestMatcher("/ws/.*", null, true);

private RequestMatcher wgetMatcher = new RegexRequestMatcher("/wget.*", null, true);

private RequestMatcher orMatcher = new OrRequestMatcher(hessianMatcher, wsMatcher, wgetMatcher);

@Override

public boolean matches(HttpServletRequest request) {

// exclude GET|HEAD|TRACE|OPTIONS from CSRF validation

if (allowedMethods.matcher(request.getMethod()).matches()) {

return false;

}

// exclude special URLs from CSRF validation

// enforce CSRF validation on all others

return !orMatcher.matches(request);

}

}



AJAX 요청의 경우 요청전에 다음과 같은 헤더 설정이 필요하다


(function($) {

    //for csrf
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    
	$.ajaxSetup({
	    beforeSend: function(xhr) {
	        xhr.setRequestHeader("AJAX", true);
	        //for csrf
	        xhr.setRequestHeader(header, token);
	     },
	     error: function(xhr, status, err) {
	        if (xhr.status == 401) {
	            alert("인증에 실패 했습니다. 로그인 페이지로 이동합니다.");
	             $(".b-close").click();
	            location.href = "/login/logout";
	         } else if (xhr.status == 403) {
	            alert("세션이 만료가 되었습니다. 로그인 페이지로 이동합니다.");
	            $(".b-close").click();
	              location.href = "/login/logout";
	         }
	     }
	});


})(jQuery);