zoukankan      html  css  js  c++  java
  • Spring Security笔记:解决CsrfFilter与Rest服务Post方式的矛盾

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

    1     <http ...>
    2         ...
    3         <csrf />        
    4     </http>

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

    复制代码
    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

    复制代码
     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

    复制代码
     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。

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

    复制代码
     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验证的范围之外了.

    https://blog.csdn.net/cwfreebird/article/details/50433188

  • 相关阅读:
    改造vant日期选择
    css3元素垂直居中
    npm综合
    (转)网页加水印方法
    Mac下IDEA自带MAVEN插件的全局环境配置
    隐藏注册控件窗口
    High performance optimization and acceleration for randomWalk, deepwalk, node2vec (Python)
    How to add conda env into jupyter notebook installed by pip
    The Power of WordNet and How to Use It in Python
    背单词app测评,2018年
  • 原文地址:https://www.cnblogs.com/softidea/p/10316841.html
Copyright © 2011-2022 走看看