【问题标题】:Prevent Cross-Site Request Forgery in a Spring WebFlow Application在 Spring WebFlow 应用程序中防止跨站点请求伪造
【发布时间】:2011-02-15 04:26:23
【问题描述】:

我正在寻找一种(希望是直截了当的)方法来为基于 Spring WebFlow 2 构建的应用程序添加 CSRF 保护。

首选可以很好地迁移到 Spring WebFlow 3(发布时)的方法。

【问题讨论】:

    标签: security spring-security csrf spring-webflow


    【解决方案1】:

    阻止 CSRF 的最简单方法是检查引用者 request.getHeader("referer"); 以确保请求来自同一个域。这个方法被CSRF Prevention Cheat Sheet覆盖了。

    这种 CSRF 保护系统在内存要求有限的嵌入式网络硬件上很常见,摩托罗拉在他们的大多数硬件上都使用了这种方法。这不是最安全的 CSRF 保护,基于令牌的保护更好,但仍然可以使用 xss 绕过这两个系统。基于令牌的 CSRF 保护的最大问题是需要花费大量时间来返回并修复每个请求,并且您可能会错过一些请求。

    实现此功能的一种安全方法是检查所有传入 POST 请求的引用者,并将 POST 用于更改密码、添加用户帐户、执行代码、进行配置更改等敏感功能。 GET 应该只用于导航或搜索,基本上 GET 对任何不会导致状态更改的东西都是安全的。

    确保使用xss scanner 测试您的网站。

    【讨论】:

    • 请注意,某些高级用户将关闭引用标题(出于隐私原因),并且您必须小心书签(尽管人们确实不应该为 POST 页面添加书签),请务必重定向处理 POST 数据后浏览器转到不同的页面。
    • 我知道这篇文章已经过时了,但它在我的搜索中是谷歌的热门搜索。请不要听从这个建议。引用标头是可欺骗的。有关更多信息,请参阅此内容:stackoverflow.com/questions/1413930/…
    • @John.Larison 是的,在您自己的浏览器上欺骗您的引用者非常容易,但是在 CSRF 攻击中不可能这样做。请参阅 OWASP CSRF 预防备忘单,避免传播明显不正确的信息。
    • 困难在于如果你想从这样的检查中排除一些“页面”。对于我们的非 Web-Flow 应用程序,我们通过排除“直接”页面 URL 来做到这一点。但是使用 Web Flow,所有“页面”共享一个 URL。
    • @dbreaux 只要所有页面共享同一个,那么您就可以通过简单地检查引用者或来源来防止攻击者拥有的域利用与 CSRF 的用户会话。
    【解决方案2】:

    OWASP 有很好的防止 CSRF 攻击的指南here:

    检查Referer 标头当然是最简单的,并且至少记录Referer 是第3 方或空的实例是一个好主意。然而,有几个缺点使得单独使用 referer 不可靠:

    • 公司防火墙可能会出于隐私原因剥离引用标头
    • 从 HTTPS 移动到 HTTP 时不发送引用者
    • 在 CFRF 攻击中,通常很难“伪造”referer,但使用元刷新标签可以是 done

    幸运的是,WebFlow 可以很容易地实现自定义唯一的 token-per-flow-invocation CSRF 过滤器(您可能不必修改任何视图/表单)!

    首先,每当流启动时,使用 FlowExectionListener 创建一个新的随机令牌并将其存储在 flowScope 中。然后,每当发出事件信号时,验证提交的令牌(作为请求中的参数提交)是否等于 flowScope 中存储的值。

    然后,配置一个自定义 FlowUrlHandler,它将“_token”参数附加到生成的 URL,因此,如果您一直使用 ${flowExecutionUrl} 来引用您的流程,那么每当您 POST/GET 回您的流程时,令牌都会自动附加。要从 FlowUrlHandler 内部从 flowScope 获取令牌,我不得不求助于使用 RequestContextHolder

     private String retrieveToken() {
        RequestContext requestContext = RequestContextHolder.getRequestContext();
        if (requestContext == null) {
            return null;
        }
        return (String) requestContext.getFlowScope().get(CsrfTokenFlowListener.TOKEN_NAME);
    }
    ...
    

    每当您输出 ${flowExecutionUrl} 时,此方法都会包含 CSRF 令牌 - 对于 GET 和 POST,如果您使用的是 post-redirect-get,则可以确保 CSRF 令牌不会出现在 URL 中吧。

    我会告诫不要只检查 POST 的 CSRF 令牌:

    WebFlow 和许多其他 Web 框架不区分 GET 和 POST - 默认情况下,您通常可以使用 GET 来执行您对 POST 所做的任何事情,除非您自己验证请求方法(无论如何这都是个好主意)。因此,想要绕过您的 CSRF 过滤器的攻击者只需执行 GET 而不是 POST。

    编辑:在 ${flowExecutionUrl} 中包含 CSRF 令牌需要注意的一个缺点是 CSRF 令牌很可能总是作为请求 URL 的一部分发送(因为它会是一部分HTML 表单的 'action' 属性),并且从不在 POST 正文中。在请求 URL 中包含敏感信息并不是很好,因为它更有可能记录在服务器/ISP 日志中。另一种方法是在每个包含 CSRF 令牌的表单中添加一个隐藏的输入,并且只对 POST 请求强制其存在。

    【讨论】:

      猜你喜欢
      • 2014-08-31
      • 1970-01-01
      • 1970-01-01
      • 2019-05-26
      • 1970-01-01
      • 2011-05-17
      • 2014-10-09
      • 2020-08-25
      • 2014-06-02
      相关资源
      最近更新 更多