• 再谈Spring MVC中对于CSRF攻击的防御


    在Spring MVC应用中实施CSRF防御, 一般会采用 EYAL LUPU 的方案,该方案的基本思路是在生成表单时在其中插入一个随机数作为签名,在表单提交后对其中的签名进行 验证 ,根据 验证 的结果区分该表单是否是经由应用签署的合法表单。如果签名不正确或不存在签名,则说明请求可能已被劫持。


    EYAL LUPU方案的巧妙之处在于,通过使用HandlerInterceptorAdapter和Spring3.1中新引入的ReuqestDataValueProcessor这一对组合,使得签名和验证的过程无缝地集成到现有应用中。Controller或Model层的对象可以仍然只关心自己的业务逻辑,完全不必考虑CSRF过程的存在;唯一的限制是在View层,必须使用Spring的<form>标签来渲染表单。

    对请求的验证在拦截器的preHandle方法中,当验证通过后,方法返回true,请求将沿着处理链继续传递;但如果验证失败,方法返回false,请求将被截停,并发送一个HTTP 400的状态代码作为响应。

    如果没有在web.xml中使用error-page为应用自定义错误页,400状态码将直接被发送给客户端浏览器,浏览器会显示一个缺省的错误页面,到目前为之一切都很完美。

    但如果使用error-page指定了错误页面,问题来了,Servlet容器会首先根据响应状态码把原始的请求转发(forward)给具体的错误页面,然后该错误页面才被发送到客户端浏览器。需要注意的是,由于我们使用了拦截器,这次forward请求会再次被拦截,preHandle方法中的验证过程也会再次被触发,如果不加处理的话,会再次验证失败,因为具体的请求仍然是最初的请求。

    解决的方案如下:
    1. 在Spring的dispatcher-servlet中加入mvc:default-servlet-handler。
    这样做的目的是确保未被Dispatcher实际处理的请求,例如向错误页面的转发或对静态资源的访问等,会被传回给Servlet容器。

    2. 修改preHandle方法,在方法的开始检测方法的第三个参数的类型。
    该参数代表处理链中即将处理请求的下一个对象,如果该参数是DefaultServletHttpRequestHandler类的实例,则说明请求即将交由Servlet容器处理,对于此类请求直接放行即可。

    3. 最后,确保所有errro-page中声明的URL不会被任何Controller处理,也不会被ResourceHttpRequestHandler处理。
    被Controller处理过就没机会沿处理链将请求交给Servlet容器了。另外,应用 一般 会在dispatcher中用mvc:resources声明静态资源,如果把错误页面也包含进来,请求会在被交给DefaultServletHttpRequestHanlder前先被 ResourceHttpRequestHandler匹配到,后者为了优化对静态资源的处理,默认是只支持GET和HEAD方法的,而此时的请求是从表单POST来的,因此会引发一个Request method 'POST' not supported错误,而浏览器端只能得到一个405响应,无法显示预期的错误页页面。

    调整后的preHandle方法类似下面这样:
    public boolean preHandle(HttpServletRequest request,
                   HttpServletResponse response, Object handler) throws Exception {
    
              if (handler instanceof DefaultServletHttpRequestHandler) {
                   return true;
              }
              
              if (!request.getMethod().equalsIgnoreCase(
                        WebContentGenerator.METHOD_POST)) {
                   // 忽略非POST请求
                   return true;
              } else {
                   // 验证CSRF签名
                   //if (passed)
                   //     return true;
                   //else {
                   //     response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                   //               "Bad or missing CSRF value");
                   //     return false;
                   //}
              }
    } 



  • 相关阅读:
    搭建一键化编译汇编语言的环境
    Windows内核中的CPU架构8任务段TSS(task state segment)
    80866中断
    x86132位x86 处理器编程架构
    80861计算机的启动过程
    Android 10升级至Android 11后关于startActivity启动应用抛异常处理方法
    通过AndroidJUnit4框架发现用例不会按顺序执行,变成随机了
    2021年11个我们喜爱的DevOps开源工具
    2021年终总结
    CF1204C Anna, Svyatoslav and Maps
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3087634.html
Copyright © 2020-2023  润新知