基于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验证的范围之外了.

Spring Security笔记:解决CsrfFilter与Rest服务Post方式的矛盾的更多相关文章

  1. Spring Security笔记:HTTP Basic 认证

    在第一节 Spring Security笔记:Hello World 的基础上,只要把Spring-Security.xml里改一个位置 <http auto-config="true ...

  2. 【Spring学习笔记-MVC-4】SpringMVC返回Json数据-方式2

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  3. 【Spring学习笔记-MVC-3】SpringMVC返回Json数据-方式1

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  4. Spring Security笔记:自定义Login/Logout Filter、AuthenticationProvider、AuthenticationToken

    在前面的学习中,配置文件中的<http>...</http>都是采用的auto-config="true"这种自动配置模式,根据Spring Securit ...

  5. Spring Security笔记:Remember Me(下次自动登录)

    前一节学习了如何限制登录尝试次数,今天在这个基础上再增加一点新功能:Remember Me. 很多网站,比如博客园,在登录页面就有这个选项,勾选“下次自动登录”后,在一定时间段内,只要不清空浏览器Co ...

  6. Spring Security笔记:使用数据库进行用户认证(form login using database)

    在前一节,学习了如何自定义登录页,但是用户名.密码仍然是配置在xml中的,这样显然太非主流,本节将学习如何把用户名/密码/角色存储在db中,通过db来实现用户认证 一.项目结构 与前面的示例相比,因为 ...

  7. Spring Security笔记:Hello World

    本文演示了Spring Security的最最基本用法,二个页面(或理解成二个url),一个需要登录认证后才能访问(比如:../admin/),一个可匿名访问(比如:../welcome) 注:以下内 ...

  8. Spring Security笔记:登录尝试次数限制

    今天在前面一节的基础之上,再增加一点新内容,默认情况下Spring Security不会对登录错误的尝试次数做限制,也就是说允许暴力尝试,这显然不够安全,下面的内容将带着大家一起学习如何限制登录尝试次 ...

  9. Spring Security笔记:使用BCrypt算法加密存储登录密码

    在前一节使用数据库进行用户认证(form login using database)里,我们学习了如何把“登录帐号.密码”存储在db中,但是密码都是明文存储的,显然不太讲究.这一节将学习如何使用spr ...

随机推荐

  1. JAVA同步容器和并发容器

    同步容器类 同步容器类的创建 在早期的JDK中,有两种现成的实现,Vector和Hashtable,可以直接new对象获取: 在JDK1.2中,引入了同步封装类,可以由Collections.sync ...

  2. MySQL数据库的导入和导出

    1.导入数据库 在命令行下输入: mysql -u username -p test < /home/data/test.sql 说明: username                   是 ...

  3. 按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。 创建第

    package com.hanqi.test; public class jidongche { private String chepaihao;//车牌号 private int speed;// ...

  4. android xml 布局错误(黑掉了)Missing styles. Is the correct theme chosen for this layout?

    发现在调整页面的时候 ,老是报以下错误,导致无法静态显示ui效果. Missing styles. Is the correct theme chosen for this layout? Use t ...

  5. js中的继承

    js中继承的实现方式很多,此处给出两种常用方式. <!DOCTYPE html> <html> <head> <meta charset='UTF-8'> ...

  6. ResultSet rs = stmt.executeQuery(sql); 返回值问题判断

      JAVA  ResultSet rs = stmt.executeQuery(sql);  //查询返回的结果集不管是否查到,rs都不是null,那么问题是怎么判断查找不到来执行一个提示“账号或者 ...

  7. keil 怎样新建工程,编写代码?

    打开keil uversion 4 新建工程 新建的工程名字,点击保存. 选择 cpu 单片机芯片 Atmel ----> AT89C51 不用将汇编代码加入工程,选择 “否” 新建文件,注意这 ...

  8. iOS 内存错误调试(EXC_BAD_ACCESS)

    内存错误crash现场: Thread堆栈: 有可能是访问被释放对象造成,根据现场并不能找到具体哪个对象出现内存错误. 1.开启僵尸对象调试 Edit Scheme->Debug->Dia ...

  9. stm32 USART rs485 rs232

    转载自:http://www.cnblogs.com/chineseboy/archive/2013/03/06/2947173.html 前题: 前段时间,在公司调试了一个项目,很简单,但对于初学的 ...

  10. webkit浏览器常见开发问题

    前段时间有人问我一个简单的问题,html如何创建解析的? 我讲了一大堆,什么通过DocumentLoader, CachedResourceLoader, CacheResource, Resourc ...