前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Security笔记:解决CsrfFilter与Rest服务Post方式的矛盾

Spring Security笔记:解决CsrfFilter与Rest服务Post方式的矛盾

作者头像
菩提树下的杨过
发布2018-01-19 11:10:56
1.1K0
发布2018-01-19 11:10:56
举报

基于Spring Security+Spring MVC的web应用,为了防止跨站提交攻击,通常会配置csrf,即:

代码语言:javascript
复制
1     <http ...>
2         ...
3         <csrf />        
4     </http>

如果应用中有Post方式访问的Rest服务(参考下面的代码),会很不幸的发现,所有POST方式请求的服务会调用失败。

代码语言:javascript
复制
1     @RequestMapping(value = "/user/create", method = RequestMethod.POST)
2     @ResponseBody
3     public UserInfo createUser(@RequestBody(required = true) UserInfo user,
4             HttpServletRequest request, HttpServletResponse response)
5             throws Exception {
6         ...
7     }

原因在于:启用csrf后,所有http请求都被会CsrfFilter拦截,而CsrfFilter中有一个私有类DefaultRequiresCsrfMatcher

代码语言:javascript
复制
 1     private static final class DefaultRequiresCsrfMatcher implements RequestMatcher {
 2         private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
 3 
 4         /* (non-Javadoc)
 5          * @see org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.servlet.http.HttpServletRequest)
 6          */
 7         public boolean matches(HttpServletRequest request) {
 8             return !allowedMethods.matcher(request.getMethod()).matches();
 9         }
10     }

从这段源码可以发现,POST方法被排除在外了,也就是说只有GET|HEAD|TRACE|OPTIONS这4类方法会被放行,其它Method的http请求,都要验证_csrf的token是否正确,而通常post方式调用rest服务时,又没有_csrf的token,所以校验失败。

解决方法:自己弄一个Matcher

代码语言:javascript
复制
 1 package com.cnblogs.yjmyzz.utils;
 2 
 3 import java.util.List;
 4 import java.util.regex.Pattern;
 5 
 6 import javax.servlet.http.HttpServletRequest;
 7 
 8 import org.springframework.security.web.util.matcher.RequestMatcher;
 9 
10 public class CsrfSecurityRequestMatcher implements RequestMatcher {
11     private Pattern allowedMethods = Pattern
12             .compile("^(GET|HEAD|TRACE|OPTIONS)$");
13 
14     public boolean matches(HttpServletRequest request) {
15 
16         if (execludeUrls != null && execludeUrls.size() > 0) {
17             String servletPath = request.getServletPath();
18             for (String url : execludeUrls) {
19                 if (servletPath.contains(url)) {
20                     return false;
21                 }
22             }
23         }
24         return !allowedMethods.matcher(request.getMethod()).matches();
25     }
26 
27     /**
28      * 需要排除的url列表
29      */
30     private List<String> execludeUrls;
31 
32     public List<String> getExecludeUrls() {
33         return execludeUrls;
34     }
35 
36     public void setExecludeUrls(List<String> execludeUrls) {
37         this.execludeUrls = execludeUrls;
38     }
39 }

这里添加了一个属性execludeUrls,允许人为排除哪些url。

然后在配置文件里,这样修改:

代码语言:javascript
复制
 1     <http entry-point-ref="loginEntryPoint" use-expressions="true">
 2         ...
 3         <intercept-url pattern="/rest/**" access="permitAll" />
 4         ...
 5         <csrf request-matcher-ref="csrfSecurityRequestMatcher"/>        
 6     </http>
 7     
 8     <beans:bean id="csrfSecurityRequestMatcher" class="com.cnblogs.yjmyzz.utils.CsrfSecurityRequestMatcher">
 9         <beans:property name="execludeUrls">
10             <beans:list>
11                 <beans:value>/rest/</beans:value>
12             </beans:list>
13         </beans:property>
14     </beans:bean>

这里约定所有/rest/开头的都是Rest服务地址,上面的配置就把/rest/排除在csrf验证的范围之外了.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-01-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档