CSRF:我可以使用 cookie 吗?
Posted
技术标签:
【中文标题】CSRF:我可以使用 cookie 吗?【英文标题】:CSRF: Can I use a cookie? 【发布时间】:2011-05-26 16:37:40 【问题描述】:可以将 CSRF 令牌放入 cookie 中吗? (并且在每种形式中,作为隐藏输入,所以我可以检查它们是否匹配,当然)我听到有人说这样做违背了令牌的全部目的,尽管我不明白为什么。我觉得这很安全。
如果它是安全的,是否比将令牌放在 URL 中更不安全?
还有其他方法吗?
我可以在哪里阅读有关该主题的更多信息?
更新:到目前为止,没有人能告诉我cookie方法是如何不安全的,如果它仍然必须匹配表单中的令牌,攻击者应该无法获得,除非他使用了另一种 hack,例如 XSS,这是另一回事,但在使用 cookie 和 url 令牌之间仍然没有区别。
UPDATE 2:好的,好像一些著名的框架使用这种方法,所以应该没问题。谢谢
【问题讨论】:
双重提交 cookie 方法有效,但要注意这种方法的 security implications。 由于实现双重提交cookie(或Angular声称正在使用的cookie到标头令牌技术)的这些影响似乎很棘手,即使对于提到的更流行的框架here(video ) 【参考方案1】:如果您决定将 CSRF 令牌放入 cookie 中,请记住将该 cookie 标记为 HttpOnly
。如果您的站点存在跨站点脚本漏洞,黑客将无法读取 CSRF 令牌。您可以在任何现代浏览器控制台中使用命令console.log(document.cookie)
检查可由 javascript 读取的 cookie。如果您有会话 cookie 或其他敏感 cookie,这些也应标记为 HttpOnly
。
进一步阅读:
https://www.owasp.org/index.php/HttpOnly
【讨论】:
您将如何读取令牌然后将其与客户端的标头(=双重提交)一起发送?仅当服务器还提供带有隐藏输入字段的表单时,才可能将 CSRF 令牌放入受保护的 cookie 中。许多 API 不提供表单,因此您必须能够使用 Javascript 读取 CSRF-token。所以我想一个更好的方法是确保没有 XSS 漏洞。 @ChristianBenke 为什么不能在服务器端呈现表单,包括服务器必须知道的令牌?还是您的意思是高级框架,其中一个不再使用模板,不提供在表单中包含令牌值的功能? @Zelphir 我写了“客户端”。因此,例如,如果您有 REST-API,则服务器不提供模板和表单。 HttpOnly 对于存储会话 ID 以防止 XSS 攻击的 cookie 来说是绝对必须的,但 CSRF 是另一个问题。为了防止 CSRF,客户端必须知道 CSRF 令牌,无论它是在表单的隐藏字段中,还是通过 JavaScript 作为 ajax 调用的标头附加。【参考方案2】:查看Encrypted Token Pattern,它允许无状态 CSRF 保护,而无需在服务器上存储令牌。
【讨论】:
【参考方案3】:“CSRF 之所以有效,是因为许多站点使用 GET 请求来执行命令。”,所以,许多站点并没有按预期使用 GET 方法,因为这些请求必须是幂等的:see the rfc2616。
“CSRF 参数已经存在于 cookie 中,它与会话一起发送。” 那怎么做呢?
cookie 仅用于具有令牌存储,当我们将令牌设置在隐藏的输入字段中时的 DOM。一段 javascript 必须从这个 cookie 中获取令牌值,并将其设置为 URL、请求正文或请求标头中的参数。它将使用存储在会话中的值在服务器上进行检查。这就是 Django 处理 CSRF 令牌的方式。
由于跨域浏览器保护,Javascript 无法从另一个域访问 cookie,所以我不知道恶意用户如何强制某人通过伪造请求发送正确的令牌。使用 XSS,是的,但是 XSS 击败了常见的 CSRF 对策。
我更喜欢澄清这一点,因为我认为这是一个重要的问题,而且不容易处理。
GET 请求必须用于获取资源和/或显示其数据,它不得用于更改其状态(删除、属性递增或任何更改) )。
CSRF 验证必须在服务器端完成,这似乎很明显,但我把它作为一个提醒。 如果您遵守此建议,此方法不能成为攻击媒介。
【讨论】:
请注意idempotent != safe
。比如GET http://example.com/api/item/123/delete
可以实现幂等(即无论GET提交1、2、3、...、N次,结果都是一样的)。
“可能实现幂等”,但它不应该:在调用此删除端点后状态已更改,并且应以 HTTP 202 Accepted 响应(如果资源尚未被删除/更改),不是 200 OK(已成功删除)。有最佳实践,因此,永远不应该将 GET 用于输出资源当前表示的其他任何事情。
我同意 GET
应该 仅用于没有明显副作用的请求,但阅读 HTTP 规范的人可能会遵循“幂等”部分,这允许更多效果。
@David:这不是幂等的意思。查看HTTP method definition specification。根据规范,PUT 和 DELETE 是幂等的,但它们不是安全方法。【参考方案4】:
使用 cookie 有效,并且是一种常见做法(例如 Django uses it)。由于同源策略,攻击者无法读取或更改cookie的值,因此无法猜测正确的GET/POST参数。
【讨论】:
重要提示: 服务器必须始终检查表单提交的 CSRF 值与通过 cookie 接收的值是否匹配。除非服务器使用 POST(或 GET)数据交叉检查来自 cookie 的数据,否则 CSRF 保护不起作用。 @MikkoRantalainen 这并不重要。这至关重要——否则魔鬼可以发送“删除我的帐户链接”——cookie 将被发送和授权的地方。所以必须进行匹配。 什么我不明白:恶意网站的攻击者不能使用JavaScript来读取cookie吗?浏览器是否默认不允许读取其他网站的 cookie? @Zelphir 是的,正如我所说,same-origin policy。 @Aerovistae 是的,这个想法是你在生成表单时将一个值放入表单中,在收到它时将其读回,两个匹配的值证明提交表单的人也可以阅读它(=具有同源访问权限)。 Cookie 和会话是保持该值的两种直接方式,以便服务器知道如何验证。会话稍微安全一点,因为您可以为站点的不同区域使用不同的值,并且您不必担心子域/父域攻击;它们也稍微难以实施。【参考方案5】:使用 cookie 违背了 CSRF 的目的。原因如下:
CSRF 之所以有效,是因为许多站点使用 GET 请求来执行命令。假设 Bob 有某种管理网络帐户,并且他已登录。可以提出一些请求,例如:
http://somesite.com/admin/whatever.php?request=delete_record&id=4
所以现在 Bob 被链接到一个攻击站点(有人试图弄乱他的数据)。然后,攻击者将上述 URL 加载到图像中,可能带有另一个 ID,并删除了一些其他记录。浏览器加载它是因为 Bob 已经登录到他的管理站点,所以他有一个有效的会话。
CSRF 试图通过向交易添加安全参数来消除这种情况。该参数应在每个请求上轮换,然后由浏览器重新发送。使 URL 看起来像这样:
http://somesite.com/admin/whatever.php?request=delete_record&id=4&csrf=<some long checksum>
这个想法是,现在攻击者必须猜测“一些长校验和”才能发起攻击。如果校验和在每个请求上都很好地轮换,那几乎是不可能的。
但是,如果您将该校验和存储在 cookie 中,您将回到第 1 格。攻击者不再需要猜测它。他只是制作原始 URL。 CSRF 参数已经存在于 cookie 中,它与会话一起发送。它并不能阻止不安全行为的发生。
【讨论】:
我看不出这是一个完美的答案,如果它说攻击者只需要原始 URL:同样,攻击者如何使表单令牌和 cookie 令牌匹配?如果我的网站易受 XSS 攻击,那是完全不同的事情,我仍然看不出它比在 URL 中使用令牌更不安全。如果攻击者可以通过 XSS 从表单中获取令牌,那么他也可以从 URL 中获取令牌。我错了吗? @HappyDeveloper - 是的,POST 也可能发生 CSRF。 GET 更常见,因为它更容易。表单标记必须匹配 cookie 中显示的任何内容。所以攻击者不需要做任何事情。他只是将请求发回,然后您的服务器会读取 cookie。 @HappyDeveloper 你不知道发生了什么。请阅读 CSRF 最基本的介绍,以及 OWASP CSRF 预防备忘单。 @Cfreak 此外,基于 POST 的 CSRF 漏洞利用与 GET 一样普遍且易于利用。您只需调用document.getElementById(1).submit()
以在查看表单时自动提交表单。
从(至少当前版本的问题)可以清楚地看出,HappyDeveloper 还打算通过 HTTP 参数(通过隐藏的表单字段)传递令牌,然后将其与 cookie 进行交叉检查。这是一种完全可以接受的防止 CSRF 攻击的方法。另外,不用担心黑客使用 XSS 从 cookie 中窃取令牌。如果攻击者可以将 XSS 放置在您的网站上,那么您对 CSRF 的担忧要大得多,并且必须首先处理 XSS 问题。以上是关于CSRF:我可以使用 cookie 吗?的主要内容,如果未能解决你的问题,请参考以下文章