【问题标题】:CSRF (Cross-site request forgery) attack example and prevention in PHPPHP中的CSRF(Cross-site request forgery)攻击示例和预防
【发布时间】:2011-02-01 08:41:10
【问题描述】:

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

http://mysite.com/vote/25

这将对第 25 项进行投票。我只想将其提供给注册用户,并且仅当他们想要这样做时。现在我知道有人在网站上忙的时候,有人给他们这样的链接:

http://mysite.com/vote/30

那么投票将是他在该项目上的位置,而他不想这样做。

我看过explanation on the OWASP website,但我不是很明白

这是 CSRF 的一个例子,我该如何防止这种情况。我能想到的最好的事情是在链接中添加一些东西,比如哈希。但是,在所有链接的末尾放置一些东西会很烦人。有没有其他方法可以做到这一点。

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

【问题讨论】:

    标签: php csrf owasp


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      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 请求进行投票,攻击者将无法在其网站(或第三方网站)上制作表单,因为他不知道受害者网站与其用户之间的秘密。

      <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>
      

      【讨论】:

        【解决方案3】:

        OWASP 有一个用于 PHP 的 CSRFGuard 和一个用于 PHP 的 ESAPI,这是我很久以前为 XMB -> UltimaBB -> 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

        谢谢, 安德鲁

        【讨论】:

          【解决方案4】:

          这可能成为 CSRF 的一个例子,如果:

          • 获取该链接(例如通过&lt;img&gt; 标签):伪造
          • 来自另一个站点:跨站点


          例如,如果我可以在 stackoverflow 的 HTML 源代码中注入这个 &lt;img&gt; 标签 (我可以,因为 stackoverflow 允许在他的帖子中使用 &lt;img&gt; 标签)

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

          你只会投票给那个项目 ;-)


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

          基本思路是:

          • 生成页面时:
            • 生成唯一令牌
            • 将其存储在用户的会话中
            • 并将其放在页面的链接中——看起来像这样:http://mysite.com/vote/30?token=AZERTYUHQNWGST
          • 调用投票页面时:
            • 检查令牌是否存在于 URL 中
            • 检查它是否存在于用户的会话中
            • 如果不是 => 不登记投票

          有这样的想法:

          • 令牌的生命周期不长,而且难以猜测
          • 这意味着你的攻击者
            • 只有几分钟的窗口,在此期间他的注射将有效
            • 一定要善于猜测^^
            • 必须为每个用户生成不同的页面。


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

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


          另一个想法(这不是完全安全,但有助于防止不知道如何强制 POST 请求的人),将仅在人们投票时接受 POST 请求:

          • 浏览器正在为注入的标签发送 GET 请求
          • 由于此 URL 正在修改一些数据,无论如何,它不应该与 GET 一起使用,而只能与 POST 一起使用

          但请注意,这并不完全安全:(可能?)可以通过一些 Javascript 来强制/伪造 POST 请求。

          【讨论】:

          • 你说得对,伪造 GET 就像伪造 POST 请求一样容易。虽然我不同意必须有一个过期的令牌。如果攻击者能够获取您的会话数据,那么您遇到的麻烦比一些额外的投票更大。但是您建议的修复仍然有效,因为密钥只是在 Cookie 和请求数据中具有令牌/随机值(保存在 cookie 中或绑定到用户会话密钥)。
          • 感谢两位的建议。我将更改所有链接以获取此令牌。我不得不同意这是一种更省钱的方法。但是我不打算实现令牌到期,我同意 MygGaN 的这一点。
          • 你们中的任何人都知道当我使用 AJAX 进行投票时该怎么做。我是否应该在用户在页面上时重复使用相同的密钥,并且只在他刷新时生成一个新令牌。或者我是否必须在投票完成时为所有链接提供一个新令牌。
          • 不确定该问题是否有明确的答案,但您必须认为“过于频繁”刷新令牌会导致麻烦;特别是,如果用户在他的浏览器中打开了您网站上的多个选项卡,并且令牌从其中一个发生更改,该怎么办?
          • 修改服务器状态的操作应该始终需要 POST 请求,否则网络爬虫、预爬虫等。可能会触发状态变化
          猜你喜欢
          • 1970-01-01
          • 2014-08-27
          • 1970-01-01
          • 2013-05-06
          • 2018-01-08
          • 2013-04-29
          • 2015-10-02
          • 2014-11-29
          • 1970-01-01
          相关资源
          最近更新 更多