【问题标题】:PHP CSRF AttackPHP CSRF 攻击
【发布时间】:2013-05-06 07:15:26
【问题描述】:

我想知道这段代码是否足够强大以防止对 PHP Form 的 CSRF 攻击?

<?php
session_start();
session_regenerate_id(true);

if (isset($_POST['submit'])) {
if (isset($_SESSION['token']) && ($_POST['token'] == $_SESSION['token'])) {
}
}
$token = hash('sha256', uniqid(mt_rand(), true));
$_SESSION['token'] = $token;
?>

//FORM

<form method="POST" action="page.php">
<input type="hidden" name="token" value="<?php echo $token; ?>">
<input type="submit" name="submit">
</form>

谢谢。

【问题讨论】:

  • 尝试openssl_pseudo_random_bytes 以获得良好的 CSPRNG(加密安全 RNG)

标签: php forms security token csrf


【解决方案1】:

如果受害者没有查看您网站上的任何表单,他的会话中还没有存储令牌。

如果攻击者向受害者提供一个完全没有令牌字段的表单,则受害者发出的 POST 请求将通过 CSRF 检查,因为$_POST['token']$_SESSION['token'] 都将为空。 (或两个空字符串,取决于 PHP 如何初始化未知变量。)

在检查相等性之前,您还必须检查会话中的令牌存在,如果其中任何一个测试失败,则中止。

根据您的网站,用户很可能没有看过表单,也可能是极端情况。首先检查令牌是否存在,无论您的网站上有多少表单,都没有 CSRF 攻击的可能性。

除了那个小问题,我看不到任何 CSRF 漏洞。该代码看起来可以完成这项工作。

【讨论】:

  • 我猜逻辑是只有与会话中的令牌等效的令牌的请求才会被处理。所以你的言论已经过时了。
  • @Gumbo 当代码就在问题中时,您为什么会?或者您是否猜测问题中可能没有包含更多代码,这些代码已经完成了我的建议?
  • 代码没有说明实际处理表单的条件。但我的猜测是它在最里面的if 分支内。其他任何事情都是没有意义的。
  • @Gumbo 这也是我认为的地方。漏洞在于,如果攻击者可以找到在其会话中没有令牌的受害者(即,尚未查看站点上的表单),那么他们可以导致该受害者发送没有令牌的 POST 请求,这将执行最里面的if 分支,因为 null == null。
  • 两个isset 应该可以防止这种情况发生。
【解决方案2】:

我会说它足以满足给定的目的。

uniqid(mt_rand(), true) 返回的值最多为 33 个字节:

  • 来自mt_rand的最多10个字节前缀
  • 8 字节系统时间,以秒为单位
  • 5 字节当前微秒
  • 来自内部线性同余生成器php_combined_lcg 的 10 个字节

然而,这 33 个字节并没有提供 264 位的熵,而是更少:

  • log2(231-1) ≈ mt_rand 前缀的 31 位
  • 系统时间已知(例如日期响应头字段)
  • 微秒只能有 106 个值之一,因此 log2(106) ≈ 20 位
  • LCG值为log2(109) ≈ 30

总计将近 81 个未知位。要强制执行此操作,平均需要 281/2 ≈ 1.2·1024 次猜测,才能在散列时产生给定的令牌。要处理的数据大约为 8·1013 TB。使用今天的计算机,您应该能够在大约 5.215·1017 秒内运行它。

这应该足以使攻击变得不切实际。

【讨论】:

    【解决方案3】:

    对于我支持的产品,我会说“不”。您的随机数生成器基于可预测的 rand()。此外,随机数看起来很短——它需要足够长,以至于不能在会话有效期间被暴力破解——也不能破解许多活动会话的 CSRF 令牌。

    查看OWASP page on CSRF,他们会给你很好的指导。

    【讨论】:

    • 我看不到任何暴力破解令牌的可能性。每个 POST 请求都会生成一个新令牌。在我们甚至没有研究预测mt_rand() 的输出之前,使用在受害者计算机上运行的javascript 或依靠受害者的点击触发请求来获得微秒精度已经超出了可行性。
    • @Ladadadada 实际上你是对的,但请记住,只有一个攻击者必须一次正确地做到这一点。如果这只是在 Facebook 上提出好友请求,那么也许我们不在乎。如果它正在批准 100 万美元的银行转账,那么 IMO 不值得冒险。如今,安全随机函数非常丰富。不妨使用它们。
    • @Freedom_Ben 事实上,使用更好的随机数生成器几乎没有任何危害。我听到的唯一抱怨是关于缓慢的。显然 openssl_pseudo_random_bytes() 在 Windows 上可能需要 30 秒以上。
    • @Gumbo:当我查看 mt_rand() 的文档时,它说,默认情况下,它基于 rand()。阅读您链接到的帖子,它仍然不是加密强 PRNG,而是基于时间、pid 和其他一些非常弱的种子位。
    • @Ladadadada:我对暴力破解的评论是关于哈希值的长度。就像我说的,我不知道值的范围,但如果它很小 - 比如 0-255 - 那么攻击者平均只需要提交 128 次即可获胜。
    猜你喜欢
    • 2016-01-30
    • 1970-01-01
    • 2011-09-30
    • 2020-02-16
    • 2019-04-25
    • 2018-03-05
    • 2013-08-15
    • 2019-08-19
    • 1970-01-01
    相关资源
    最近更新 更多