spring security4.2 配置CSRF防御
注:源文请参考官方手册
最经项目用到csrf,看了官方文档后,结合实际开发过程,记录下所遇到的问题,其中第1、2、3点都没有什么问题。而是在使用文件上传时遇到问题,查了比较久的时间,从怀疑xhr对象,到跨域访问(用到的插件动态创建了一个iframe),最终发现是当form设置了enctype="multipart/form-data"
之后,采用在form中插入标签的方法并不能通过验证,解决方法如4所述。其实这在官方文档,就在使用说明的下方就给出使用csrf的4个警告,当时没留意,想起这一点还是看到 multipart 后才觉得有点“眼熟”,然后再次看了之后,最终解决了上传文件失败的问题。记录下来,共勉之,同时有错的地方,还望浏览的“大虾们”不吝赐教啦
1.首先,确保在springSecurity.xml
里没有把csrf关掉,即配置文件中不要出现以下代码:
<security:http>
<!--如果需要使用csrf,请注释下行配置-->
<security:csrf disabled="true"/>
</security:http>
尽量将涉及修改资源的请求改为
POST
2.一般form表单 –参考这里
提交需要添加token,或者可以使用spring的标签<sec:csrfInput />
,页面需要引入(有些ide可以实现自动引入如idea)
<%@ taglib prefix=”sec” uri=”http://www.springframework.org/security/tags” %>
如下所示:
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}"
method="post">
<input type="submit"
value="Log out" />
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
</form>
<!--或者使用标签-->
<form method="post" action="/do/something">
<sec:csrfInput />
Name:<br />
<input type="text" name="name" />
...
</form>
3.对于Ajax
和JSON
请求–参考这里
需要在中如下设置,也有相应的spring的标签<sec:csrfMetaTags/>
:
<html>
<head>
<meta name="_csrf" content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}"/>
<!-- ... -->
</head>
<!-- ... -->
<!--或者使用标签-->
<!DOCTYPE html>
<html>
<head>
<title>CSRF Protected JavaScript Page</title>
<meta name="description" content="This is the description for this page" />
<sec:csrfMetaTags />
<script type="text/javascript" language="javascript">
<!--……-->
</head>
<!--……-->
</html
同时,需要在js中加入如下代码
$(function () {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
});
4.上传文件,Multipart–参考这里
两个可选项来使用csrf:
- 将MultipartFilter放在Spring Security之前
<filter>
<filter-name>MultipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>MultipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 在action中添加CSRF token
<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">