PHPF中的CSRF(跨站点请求伪造)攻击示例和预防

时间:2010-03-26 20:29:20

标签: php csrf owasp

我有一个网站,人们可以这样投票:

http://mysite.com/vote/25

这将对第25项进行投票。我想只为注册用户提供此选项,并且只有在他们想要这样做的情况下才能使用。现在我知道有人在网站上忙碌,有人给他们这样的链接:

http://mysite.com/vote/30
然后投票将是他在项目上的位置,而他不想这样做。

我已阅读explanation on the OWASP website,但我并不理解

这是CSRF的一个例子,我该如何防止这种情况发生。我能想到的最好的事情就是像哈希一样在链接中添加一些内容。但是,在所有链接的末尾添加一些内容会非常恼人。没有其他方法可以做到这一点。

另一件事可能有人可能会给我一些其他的例子,因为这个网站对我来说似乎很神奇。

4 个答案:

答案 0 :(得分:91)

如果符合以下条件,这可能会成为CSRF的一个例子:

  • 该链接已获取(例如,通过<img>标记):forgery
  • 来自其他网站:跨网站


例如,如果我可以在stackoverflow 的HTML源代码中注入此<img>标记(我可以,因为stackoverflow允许在他的帖子中使用<img>标记)

<img src="http://mysite.com/vote/30" />

您只需投票支持该项目; - )


通常使用的解决方案是在URL中放置生命周期有限的令牌,并在获取URL时检查此令牌是否仍然有效。

基本理念是:

  • 生成页面时:
    • 生成唯一令牌
    • 将其存储在用户的会话中
    • 并将其放在页面的链接中 - 看起来像这样:http://mysite.com/vote/30?token=AZERTYUHQNWGST
  • 调用投票页面时:
    • 检查网址中是否存在令牌
    • 检查用户会话中是否存在
    • 如果不是=&gt;不要注册投票

有这样的想法:

  • 代币生命周期不长,难以猜测
  • 这意味着您的攻击者
    • 只有几分钟的窗口,在此期间注射有效
    • 必须擅长猜测^^
    • 必须为每个用户生成不同的页面。


另请注意,用户会话在离开您的网站后保持活动时间越短,访问不良网站时仍然有效的风险就越小。

但是在这里,您必须在安全性和用户友好性之间做出选择......


另一个想法(这不是非常安全,但有助于反对人们不知道如何强制POST请求),只会在人们投票时接受POST请求:

  • 浏览器正在发送注入标记的GET请求
  • 由于此URL正在修改某些数据,无论如何,它不适用于GET,而只适用于POST

但请注意,这不是完全安全的:它可能是(可能是?)强制/伪造一个POST请求,只需要一些Javascript。

答案 1 :(得分:18)

首先,不应该使用GET请求来改变服务器上的状态,因此对于您的投票服务,我建议使用POST / PUT。这只是一个指导方针,但却是一个聪明的方法。

因此,对于您的问题,CSRF是一个客户端问题,因此您使用何种服务器语言并不重要(在您的情况下为PHP)。标准修复是相同的,如下所示:在URI / POST数据中有一个随机值,在Cookie标头中有相同的值。如果这些匹配你可以确定没有CSRF。有关如何在StackOverflow上完成此操作的信息很多,例如。 this one
祝你好运!

答案 2 :(得分:5)

OWASP有一个用于PHP的CSRFGuard和我很久以前为XMB写过的PHP的ESAPI - &gt; UltimaBB - &gt; GaiaBB。

http://code.google.com/p/gaiabb-olpc/source/search?q=function+get_new_token&origq=function+get_new_token&btnG=Search+Trunk

似乎其他一些人已经清理了这些代码并允许更强的代币:

https://www.owasp.org/index.php/PHP_CSRF_Guard

感谢, 安德鲁

答案 3 :(得分:1)

CSRF攻击中有3个玩家

  1. 受害者网站(在您的示例中为您的投票网站)[了解其登录用户的Cookie ]
  2. 您客户的浏览器(登录时)[知道他的cookie ]
  3. 攻击者网站[不知道已登录用户的cookie ]

CSRF攻击取决于两个事实

  1. 浏览器会根据每个请求自动发送cookie
  2. 我们依靠Cookie来标识我们的登录用户(例如setcookie("sessionID", "0123456789ABCDEF", time()+3600);

如果攻击者可以轻易使他人或已登录的用户要求这样做

// http://victim.website/vote/30

例如,通过将链接放在攻击者网站上或通过电子邮件发送,已登录的客户端浏览器将随此请求一起发送标识cookie(sessionID),这将使受害网站认为其已登录用户真的想投票!

但是,如果受害者的网站更加聪明,并使用其他GET或POST参数(不是cookie)验证了登录用户的请求,那么攻击者就会遇到问题,因为浏览器不会自动发送GET和POST参数,他必须猜出来。

// http://victim.website/vote/30?csrfSecret=0123456789ABCDEF

攻击者不知道csrfSecret参数,它是受害者网站与其客户之间的秘密(就像会话令牌一样),因此攻击者无法构建他想要伪造的URL。请求。

类似地,如果投票是通过POST请求进行的,则攻击者将无法在其网站(或第三方网站)上填写表格,因为他不知道受害者的网站与用户之间的秘密。 / p>

<form method="post" action="http://victim.website/vote" >
    <input type="hidden" name="vote" value="30">
    <input type="hidden" name="csrfSecret" value="????? I don't know it :(">
</form>