保护登录和评论表单免受CSRF攻击


Protecting login and comment forms against CSRF

我读了很多关于CSRF保护的文章(这是一篇很好的文章)和关于SO的各种问题,但似乎没有一篇足够的信息来回答我的问题。

我正在开发自己的CMS,我想确保我的登录和评论表单。我将允许匿名用户在我的网站上发表评论。

我网站上的所有表单都使用令牌进行保护。我已经知道了这种方法,但问题是它需要一个活动会话(也就是说,在用户登录之后)。登录和评论表单的问题在于,几乎任何人都可以访问它们,并且不需要您登录—在这种情况下,防止CSRF的最佳保护是什么?

在上面的链接中,我读到当用户尝试登录时,可以创建一个"预会话",然后继续使用通常的反csrf方法(如为用户的会话分配令牌),但我不知道如何实现这一点。

引用头是一个弱的解决方案,所以我想我不应该麻烦。据我测试,Origin标题只支持Google Chrome。那自定义标头呢?XMLHTTPRequest似乎是一种可能性,然而,我花了三个多小时在Google上查找有关如何在其网站上实现这种安全措施的一些信息。但是,即使我可以使用自定义报头,难道它不是无用的,因为HTTP报头可以完全伪造吗?

所以,问题是:我应该如何保护我的登录和评论表单免受CSRF的侵害?

编辑:这里是我上面提供的链接中的一些额外信息:

我们建议严格的Referer验证来防止登录CSRF因为登录表单通常通过HTTPS提交,其中Referer标头对于合法请求是可靠的。如果一个登录请求缺少Referer标头,站点应该拒绝请求进行防御防止恶意打压。

秘密验证令牌可以防御登录CSRF,但开发人员经常忘记实现防御是因为,在登录之前,有没有要绑定CSRF令牌的会话。使用秘密验证为了防止登录CSRF,站点必须首先创建一个实现基于令牌的CSRF保护,然后认证成功后转换到真实会话

读了上面的引语后,我无法结束这场争论。其中一个提到了使用引用头,但我不太确定它是否真的增加了web应用程序的安全性。

Edit 2:使用验证码怎么样?

CSRF问题与某人使用登录的用户凭据提交内容有关。这是很有问题作为一个恶意网站可以做的东西的人只是浏览到你的网站。如果您谈论的是可以匿名使用的表单,无需登录,则CSRF风险要小得多,因为从另一个站点向该表单发送信息所获得的收益要小得多——因为任何人都可以以相同的权限直接执行此操作。

所以我不明白为什么需要为未登录的表单保护CSRF。

如果您确实想要这样做,则会话前令牌可以在技术上类似于实际会话,但只是更轻量级的令牌。除了生成的令牌,它实际上不会包含任何其他内容。


编辑:关于使用PHP提供的$_SESSION作为会话前令牌,这是PHP的标准会话机制。如果你想用它,那么是的,就是这样。

然而,你不强迫这样做,我个人不会这样做,因为它消耗服务器内存为所有的访问者,这不是真正需要的。对于更有效的机制,基本上需要a)标识用户的cookie和b)存储在服务器端告诉cookie有效的东西(如果需要,它对谁有效,即ip)。对于更轻量级的方法,您可以创建一个令牌,将其存储在cookie中,并在表单中生成与该令牌匹配的内容作为隐藏字段,并匹配提交时的内容(如Devesh所解释的)。后者将阻止来自其他站点的表单提交,前者甚至可以防止恶意站点在您的站点上进行查找并试图设置任何cookie给最终用户。我能想到的三种方法:

  • 只是阻止来自其他网站的图像请求-使用post可以防止这个
  • 阻止表单从其他站点提交-表单隐藏字段匹配cookie阻止此
  • 防止表单提交从另一个网站做预查找在您的网站-这将需要IP验证,一些存储在服务器端,如IP在数据库中匹配的cookie

EDIT2:在验证码上,它们的主要用例是防止自动(暴力破解)登录尝试。他们也可以解决登录表单上的CSRF请求的问题,但这是多余的。为了防止暴力登录攻击,在某些情况下可能需要它们,尽管为了不降低可用性,可能需要更用户友好的东西。也许像KittenAuth:)

您无法真正保护匿名表单免受CSRF的侵害。因为其他站点可以充当常规用户。我可以创建一个网站,对匿名表单进行curl请求,并将cookie和令牌存储在变量中。然后发出第二次请求来发布表单。这个脚本并不是真正的伪造请求,而只是自动发布。

CSRF的目的是防止脚本/人员代表另一个用户执行操作。所以那就是我试图以你的身份发帖。为了防止这种情况,会话/cookie带令牌的方法是一个很好的解决方案。因为我没有办法得到你的会话和令牌,除非你的网站在其他方面有缺陷。我建议您阅读OWASP指南,以了解您应该注意哪些内容。

你应该经常做的另一件事是确保"行动"总是与POST请求,所以我不能简单地在你的论坛上链接到"http://www.yoursite.com/delete.php?id=10"的图像。如果您允许GET请求并打开包含此图像的页面,我将伪造请求。如果你只允许POST,就不会有结果。

我认为您可以通过组合添加到表单中的隐藏字段来解决CSRF问题,同时在cookie中添加相同的值并附加用户响应。当用户发回的表单尝试匹配隐藏字段值和cookie值来自请求,如果两者都匹配你很好去…

CSRF问题与某人使用登录的用户凭证提交内容有关。这是很有问题作为一个恶意网站可以做的东西的人只是浏览到你的网站。如果您谈论的是可以匿名使用的表单,无需登录,则CSRF风险要小得多,因为从另一个站点向该表单发送信息所获得的收益要小得多——因为任何人都可以以相同的权限直接执行此操作。

所以我不明白为什么需要为未登录的表单保护CSRF。

如果您确实想要这样做,则会话前令牌可以在技术上类似于实际会话,但只是更轻量级的令牌。除了生成的标记,它实际上不会包含任何其他内容。