为啥 CSRF 令牌应该在元标记和 cookie 中?

Posted

技术标签:

【中文标题】为啥 CSRF 令牌应该在元标记和 cookie 中?【英文标题】:Why CSRF token should be in meta tag and in cookie?为什么 CSRF 令牌应该在元标记和 cookie 中? 【发布时间】:2014-02-23 18:15:34 【问题描述】:

使用 将 CSRF 令牌名称和值放入 标记中需要什么,例如:

例如:

<meta content="authenticity_token" name="csrf-param" />
<meta content="4sWPhTlJAmt1IcyNq1FCyivsAVhHqjiDCKRXOgOQock=" name="csrf-token" />

我已经阅读了将 CSRF 值保留在 cookie 中的概念,但没有找到为什么要保留在 标记内。

【问题讨论】:

【参考方案1】:

CSRF 令牌通常以隐藏表单字段的形式出现。仅当您使用 javascript 时,将它们放在元标记中才有意义。 JavaScript 可以从元标记中读取标记并将它们发布到操作中。

您不希望将 CSRF 令牌放入 cookie 中,因为无论其来源如何,都会针对从 Web 浏览器到特定网站的每个请求发送 cookie。唯一的例外是 安全 cookie,它们应该遵循同源策略。

【讨论】:

在 cookie 中存储 XSRF 令牌时如果我发送请求时设置 X-XSRF-TOKEN 标头并检查标头服务器端忽略 cookie【参考方案2】:

对于prevent CSRF,您需要一个随请求一起提交的值,该值不能由恶意站点发送。身份验证 cookie 不适合,因为如果攻击者可以使浏览器向受害站点发送请求,cookie 将自动提交。

例如,通过 www.evil.com 中包含的 JavaScript 提交表单来攻击 www.example.com 上的用户会话:

<form method="post" action="https://www.example.com/executeAction">
    <input type="hidden" name="action" value="deleteAllUsers">
</form>

<script>document.forms[0].submit()</script>

在页面中存储反 CRSF 令牌是 OWASP 推荐的解决方案,用于阻止其他网站提交表单,因为 www.evil.com 无法读取用户会话中的随机令牌,因为 Same Origin Policy 阻止了 JavaScript在www.evil.com阅读www.example.com的页面内容。

这些令牌可以存储在页面内的任何位置。最常见的是它会在隐藏的表单域中,但它们也可以存储在html 5 data- attributes 中。似乎使用meta 标签只是另一种可以存储它的方式,JavaScript 可以将它包含在页面提交的任何表单中。

【讨论】:

www.evil.com 不应该能够从 www.example.com 获取用户的确切令牌,即使 SOP 已禁用(即来自 www.evil.com 的请求是单独的会话,因此应该生成一个新的令牌)。 如果使用相同的浏览器实例是相同的会话(当然禁止使用隐身或隐私浏览模式)。 www.example.com 如何知道它是否是同一个会话?来自www.evil.com 的请求没有任何令牌。 它有相同的会话,但你是对的它无法获取令牌。然而,这只是,因为 SOP 保护它。【参考方案3】:

这是因为没有什么可以阻止违规网站将数据发布到合法网站,其中可能包括您的身份验证票证和 CSRF 令牌。想象一下这个场景……取自ASP.NET

    用户使用表单身份验证登录 www.siteA.com。 服务器对用户进行身份验证。来自服务器的响应包含一个身份验证 cookie。

    用户在不注销的情况下访问恶意网站。此恶意网站包含以下 HTML 表单:

    <h1>You Are a Winner!</h1>
        <form action="http://siteA.com/api/account" method="post">
            <input type="hidden" name="Transaction" value="withdraw" />
            <input type="hidden" name="Amount" value="1000000" />
     <input type="submit" value="Click Me"/>
        </form>
    

请注意,表单操作发布到易受攻击的站点,而不是恶意站点。这是 CSRF 的“跨站”部分。

用户点击提交按钮。浏览器在请求中包含身份验证 cookie。 该请求使用用户的身份验证上下文在服务器上运行,并且可以执行任何经过身份验证的用户被允许执行的操作。

所以基本上,当 siteA.com 收到 CSRF 攻击时,它应该将 cookie 中的 CSRF 令牌与元标记中的 CSRF 令牌相匹配。合法的请求将包括两者,但是,伪造攻击将仅包括 cookie 中指定的 CSRF 令牌。

【讨论】:

【参考方案4】:

我能想到的唯一选择是让这些数据可以从 JavaScript 访问。当然,以防 cookie 仅是 http。

【讨论】:

好的,我明白了,但我仍然很困惑。非常感谢。 如果我的回答对你有帮助请记得采纳。

以上是关于为啥 CSRF 令牌应该在元标记和 cookie 中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥将刷新令牌存储在仅 HTTP 的 Cookie 中以防止 CSRF 攻击?

元标记中带有令牌的 CSRF 保护 - 为啥不能被盗?

CSRF 和 iframe

为啥恶意站点在攻击前无法通过 GET 获取 CSRF 令牌?

对 CSRF 保护策略感到困惑

注销后的 CSRF 令牌生命周期