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

6

我已经阅读了许多关于CSRF保护的文章(这是一篇好文章),以及在SO上的各种问题,但它们似乎都不足以回答我的问题。

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

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

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

引荐头部是一个弱解决方案,所以我想我不应该费心。据我测试,Origin头部仅在Google Chrome中受支持。那么自定义头部呢?XMLHTTPRequest似乎是一种可能性,但是,我已经在谷歌上花费了超过三个小时的时间查找有关如何在其网站上实现此安全措施的信息。但即使我可以使用自定义头部,HTTP头部也可以完全伪造,这不是使它无用吗?

那么问题来了:我应该如何保护我的登录和评论表单免受CSRF攻击?

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

我们建议严格的引荐验证以防止登录CSRF,因为登录表单通常通过HTTPS提交,在合法请求中可靠地存在引荐头部。如果登录请求缺少引荐头部,则站点应拒绝该请求以防止恶意抑制。

还有

秘密验证令牌可以防御登录 CSRF 攻击,但开发人员经常忘记实现该防御措施,因为在登录之前没有会话可以绑定 CSRF 令牌。要使用秘密验证令牌来保护免受登录 CSRF 攻击,站点必须首先创建一个“pre-session”,实现基于令牌的 CSRF 保护,然后在成功认证后转换为真正的会话。
读完上述引用后,我就无法结束这场争论。其中一个提到了使用 Referrer Header,但我不确定它是否确实增加了 Web 应用程序的安全性。
编辑2:使用 CAPTCHA 如何?

这可能是一个适合在Security SE上提问的问题,否则OWASP是一个关于网络安全的好资源。 - HamZa
但是为什么在SO上有这么多关于同一主题的问题呢? - Onion
在我看来,“完全”保护一个Web应用程序免受某种攻击是太宽泛了,否则我很乐意看到一个涵盖这个问题的好答案(这就是为什么我点赞的原因:))。 - HamZa
1
我完全意识到没有完美的保护措施,但我们难道不应该追求最好的吗? :) - Onion
我完全同意你的观点 :D - HamZa
4个回答

3
CSRF问题涉及使用已登录用户凭据提交内容。这是非常棘手的,因为恶意网站可以像任何一个刚进入您的网站的人一样做事情。如果您谈论的是可以匿名使用的表单,而无需登录,则CSRF风险要小得多,因为从另一个站点发布到表单中可以获得的利益要少得多——因为任何人都可以直接使用相同的权限进行操作。所以我不明白为什么需要保护未登录表单免受CSRF攻击。如果确实需要这样做,预会话令牌在技术上类似于真实会话,但更轻量级。它实际上不包含除生成的令牌之外的任何其他内容。

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

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

  • 仅防止其他站点的图像请求 - 使用POST可以防止这种情况
  • 防止来自另一个站点的表单提交 - 表单隐藏字段匹配cookie可以防止这种情况
  • 防止来自另一个站点的预先查找您的站点的表单提交 - 这需要IP验证,服务器端存储的内容,例如在数据库中与cookie匹配的IP

编辑2:关于验证码,它们的主要用途是防止自动化(暴力破解)登录尝试。它们也可以解决登录表单中CSRF请求的问题,但对此而言有些过于复杂。为了防止暴力破解登录攻击,在某些情况下可能需要使用它们,尽管可能需要采用更加用户友好的方法来不降低可用性。也许像KittenAuth这样的东西会更好:)


那么“预会话”就是我在用户登录后使用的相同$_SESSION[]变量吗?据我所知,这将要求我每次访问登录页面时都启动一个新会话并分配一个令牌。在成功登录之后,我应该首先销毁现有的会话,然后再开始一个新的会话(“完整会话”),对吗? - Onion
更改会话并不是为了防止 CSRF,而是为了防止会话劫持。其想法是用户在浏览不安全的页面时可能会受到攻击。然后在他登录后,您更改会话,因此即使他的会话被攻击,他们也无法在登录后再使用该会话。 - Hugo Delsing
@HugoDelsing 这将防止恶意网站(完全控制其内容)在我的网站上进行匿名预查,并基于此为正在浏览他们网站的某人生成HTML。 在这种情况下,IP地址不匹配。 即使恶意网站完全控制其代码,它们通常也无法像只是浏览其网站的用户那样进行预查。 - eis
第一种方法使用会话和令牌已经解决了这个问题。无需进行IP验证。因为我也无法访问用户的令牌。我只能生成自己的令牌。如果你在谈论会话劫持,那么IP验证是必要的。但与CSRF无关。 - Hugo Delsing
嗯。但说真的,防止登录表单上的CSRF攻击真的更安全吗?我的意思是,毕竟没有任何活动会话正在进行,而攻击者最坏的情况(就我所知)只是从另一个站点自动登录。 - Onion
显示剩余9条评论

0

你无法真正保护匿名表单免受CSRF攻击。因为其他网站可以像普通用户一样操作。我可以创建一个站点,对匿名表单进行curl请求,并将cookie和令牌存储在变量中。然后再发起第二个请求来提交表单。 脚本并没有伪造请求,只是自动提交。

CSRF的目的是防止脚本/人员代表另一个用户执行操作。所以这意味着我试图以你的身份发布内容。为了防止这种情况,会话/cookie与令牌方法是一个好的解决方案。因为除非你的网站在其他方面存在缺陷,否则我无法获取你的会话和令牌。我建议阅读OWASP指南,以了解应该注意哪些问题。

另一件你应该始终做的事情是确保“actions”总是使用POST 请求,这样我就不能简单地在你的论坛上放置一张图片,链接到'http://www.yoursite.com/delete.php?id=10'。如果你允许GET请求并打开包含该图片的页面,我会伪造一个请求。如果你只允许POST请求,它将没有结果。

POST 帮了一点忙,但并不是很有效 - 如果有一个允许 JavaScript 注入的网站,恶意用户可以在那里放置一个表单,并通过 js 提交它(如果需要,在框架中进行提交,以便它甚至不会显示出来)。 - eis
我在网站上只有在想要显示特定文章时才使用GET请求。我从URL中获取id值,进行清理并继续访问数据库,但在此情况下没有表单。这样做是否安全? - Onion
1
在显示(获取)数据时使用“GET”是没有问题的。通常不应该使用它来更改(发布/放置)数据。 - Hugo Delsing
是的,我记得读过不要在状态改变操作(例如将数据插入数据库)中使用GET方法。 - Onion
CSRF是关于一个Web应用程序的问题,即“无法或不能充分验证提交请求的用户是否有意提供格式良好、有效、一致的请求。”(http://cwe.mitre.org/data/definitions/352.html)特别是,它不需要受害者进行身份验证,尽管这样的受害者对攻击者来说更有价值。 - Gumbo
那么你想要验证一个匿名用户是否确实是预期的匿名用户? - Hugo Delsing

0

我认为你可以通过将隐藏字段添加到表单中,并同时在cookie中添加相同的值并附加到用户响应中来解决CSRF问题。当用户提交表单时,尝试匹配来自请求的隐藏字段值和cookie值,如果两者匹配,则可以继续进行...


Cookie方法不是很安全,您能否详细说明一下使用cookie存储令牌的方法(我只在我的Web应用程序上使用活动会话)? - Onion
您可以在此处查看:http://blog.stevensanderson.com/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/ Microsoft也使用了相同的方法来保护ASP.NET MVC。虽然没有100%安全的方法,但我们可以最大程度地提高安全性。 - Devesh

0
CSRF问题涉及到某人使用已登录用户的凭据来提交某些内容。这是非常有问题的,因为恶意网站可以像任何一个刚刚进入你的网站的人一样做事情。如果你在谈论可以作为匿名方式使用的表单,而不需要登录,那么CSRF风险要小得多,因为从另一个站点发布到表单上能够获得的利益要少得多 - 因为任何人都可以直接进行相同权限操作。
所以我不明白为什么需要保护未登录表单免受CSRF攻击。
如果您确实需要这个功能,预先生成一个会话令牌在技术上类似于真实会话,但只是更轻量级的一个。它不会包含除生成的令牌之外的其他任何东西。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接