【问题标题】:Should CSRF tokens be server-side validated?CSRF 令牌是否应该在服务器端进行验证?
【发布时间】:2014-01-05 15:42:33
【问题描述】:

首先,我想确保我的 CSRF 令牌工作流程正确无误。 服务器在我的机器上,在站点的域上设置了一个 cookie。浏览器阻止从其他域访问此 cookie。当发出 POST 请求时,我将 CSRF 令牌发送到服务器,然后将其与我的 cookie 进行比较。如果它们不一样,则返回 403 Forbidden 页面。

现在,如果我手动更改 cookie 中令牌的值并在 POST 请求中发送该新值,服务器是否应该返回 403?服务器是否需要根据存储在服务器或 cookie 上的值来验证令牌?

我在 Django 1.3 (https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/) 上使用 CSRF 保护的默认实现,它仅根据令牌验证请求中发送的令牌。

【问题讨论】:

    标签: django security csrf


    【解决方案1】:

    TL;DR: 是的,您或您使用的框架都需要有服务器端逻辑来验证 CSRF 令牌。它不能是 cookie,它必须是要求用户在您的页面上的东西,而不是点击攻击者提供的链接。


    您的工作流程非常正确。第一步是生成一个攻击者无法预测的加密随机字符串。每种编程语言都有自己的结构来执行此操作,但是 24 - 32 个字符的字符串应该可以很好地达到此目的。

    在我们进入下一步之前,让我们确保我们知道我们正在处理什么威胁 - 我们不希望攻击者代表用户发出请求,所以应该有一些东西可以访问要求用户执行操作以发送令牌的浏览器,但是,如果用户单击攻击者设置的内容,则不应发送令牌。

    鉴于此,不应该这样做的一种方法是使用 cookie。每次向设置 cookie 的域发出请求时,浏览器都会自动发送 cookie,因此这会自动破坏我们的防御。

    也就是说,让我们进入下一步,即以一种您可以在服务器端验证但攻击者无法访问的方式设置此令牌。有多种方法可以做到这一点:

    1) A CSRF 标头:这在许多 node.js/Express 安装中完成 - CSRF 令牌作为标头发送,具体而言,是 X-CSRF-Token 标头。生成此令牌后,服务器将其存储在该特定 cookie 的会话存储中。在前端,令牌存储为 JavaScript 变量,这意味着只有在该特定页面上生成的请求才能具有标头。每当发出请求时,会话 cookie(在 node.js 的情况下,连接。 sid) 并且所有 POST/PUT/DELETE 请求都需要 X-CSRF-Token。如果发送了错误的令牌,服务器会发送 401 Unauthorized,并重新生成令牌,请求用户登录。

    <script type="text/javascript">
    window.NODE_ENV = {};
    window.NODE_ENV.csrf = "q8t4gLkMFSxFupWO7vqkXXqD";
    window.NODE_ENV.isDevelopment = "true";
    </script> 
    

    2) 隐藏的表单值:很多 PHP 安装使用它作为 CSRF 防御机制。根据配置,特定于会话或特定于请求(后者是多余的,除非应用程序需要它)令牌嵌入在隐藏的表单字段中。这样,每次提交表单时都会发送它。验证方法各不相同 - 可以通过针对数据库进行验证,也可以是特定于服务器的会话存储。

    3) Double Submit Cookies:这是 OWASP 建议的一种机制,除了通过标头发送会话 cookie 之外,您还可以将其包含在提交的表单中。这样,一旦您验证会话有效,您就可以验证表单是否也包含会话变量。如果你使用这种机制,确保在验证 CSRF 之前验证用户的会话是至关重要的;否则,它会引入缺陷。

    在构建/测试此机制时,请务必注意,尽管许多实现将其限制为 POST/DELETE/PUT 事务,这是因为它自动假定所有敏感事务都通过此动词发生。如果您的应用程序使用 GET 执行敏感事务(例如激活),那么您也需要此机制用于 GET/HEAD。

    【讨论】:

      【解决方案2】:

      你如何发送令牌?

      通常,令牌应该是 cookie 的某个功能(带有密钥 - 只有服务器知道;例如 MAC)!不是 cookie。

      比流程如下: 1. 客户端发送带有 cookie 的服务器请求。 2. 服务器返回一个带有 CSRF 令牌的网页,用于不同的目的(例如,表单或只是通过 URL 的简单获取请求)。 3. 客户端执行一些操作(通过 POST 或 GET)并使用令牌(在请求正文或 URL 中)和 cookie 发送请求。 4. 服务器是无状态的,但它可以通过计算cookie(或部分cookie)上的函数(使用服务器知道的密钥)来验证请求是由同一个客户端发送的,并将输出与令牌。

      在 CSRF 的情况下,cookie 会被浏览器自动附加到请求中,但攻击者(甚至可能不知道 cookie)无法添加相应的令牌。

      我相信你应该这样做。

      现在,如果我手动更改 cookie 中令牌的值并 在 POST 请求中发送该新值,如果服务器返回一个 403与否?服务器是否需要再次验证令牌的值 存储在服务器上还是 cookie 上?

      服务器应该是无状态的(通常)。您不想针对数据库中的某个值或类似的东西验证每个请求的令牌。最好对照 cookie 进行验证。 在这种情况下,如果您更改令牌,它可能与 cookie 不匹配,您应该发送 403。

      【讨论】:

        猜你喜欢
        • 2012-12-08
        • 2015-02-07
        • 2021-08-30
        • 2010-11-10
        • 2016-09-21
        • 2017-08-15
        • 2015-03-03
        • 2023-01-12
        • 1970-01-01
        相关资源
        最近更新 更多