CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,一般缩写为CSRF或者XSRF,是一种对网站的恶意利用。为了防止跨站提交攻击,一般会配置csrf。javascript
Spring Security 为了防止跨站提交攻击提供了CSRF保护功能,该功能在Spring Security 3时就已经存在,默认是不启用,Spring Security 4默认启用了,因此由Spring Security 3升级到Spring Security 4就会有全部POST方式请求的服务会调用失败的问题,缘由在于:启用csrf后,全部http请求都被会CsrfFilter拦截,而CsrfFilter中有一个私有类DefaultRequiresCsrfMatcher。html
private static final class DefaultRequiresCsrfMatcher implements RequestMatcher { private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); /* (non-Javadoc) * @see org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.servlet.http.HttpServletRequest) */ public boolean matches(HttpServletRequest request) { return !allowedMethods.matcher(request.getMethod()).matches(); } }
从这段源码能够发现,POST方法被排除在外了,也就是说只有GET|HEAD|TRACE|OPTIONS这4类方法会被放行,其它Method的http请求,都要验证_csrf的token是否正确,而一般post方式调用rest服务时,又没有_csrf的token,因此校验失败。java
若是想禁用CSRF保护功能,可采起如下方式:jquery
Security XML配置文件中配置:web
<csrf disabled="true" />
若是你使用JAVA注解配置:ajax
@EnableWebSecurity @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable(); } }
若是正常使用CSRF:spring
对于表单域,可增长一个标签<security:csrfInput/>,这个标签会生成一个隐藏域。ide
<%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %> <form action="login" class="login-form" method="post" style="display: inline-table;"> //其余表单域 <security:csrfInput/> <button type="submit" class="btn btn-success btn-block">登 录</button> </form> //<security:csrfInput/>实际会生成<input type="hidden" name="_csrf" value="XXXXXXXXXXXXXXXXXXXX">
对于非表单域,增长<security:csrfMetaTags/>,该标签可在报文头增长crsf的token。post
<%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8"> <title>首页</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <security:csrfMetaTags/> //这个标签会生成如下内容 <meta name="_csrf_parameter" content="_csrf" /> <meta name="_csrf_header" content="X-CSRF-TOKEN" /> <meta name="_csrf" content="XXXXXXXXXXXXXXXXXX" />
最后写一个jquery提交的处理网站
(function(){ $(document).ajaxSend(function(e,xhr,opt) { if (opt.type == "POST"){ var header = $('meta[name=_csrf_header]').attr('content'); var token = $('meta[name=_csrf]').attr('content'); if (header != '' && token != ''){ xhr.setRequestHeader(header, token); } } }); })();