2

我想知道这段代码是否足够强大以防止对 PHP 表单的 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>

谢谢。

4

3 回答 3

2

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

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

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

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

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

于 2013-05-12T00:05:22.770 回答
1

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

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

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

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

  • log 2 (2 31 -1) ≈ 31 位作为mt_rand前缀
  • 系统时间是已知的(例如日期响应头字段)
  • 微秒只能有 10 6 个值之一,因此 log 2 (10 6 ) ≈ 20 位
  • LCG 值为 log 2 (10 9 ) ≈ 30

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

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

于 2013-05-12T11:37:04.697 回答
1

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

查看CSRF 上的 OWASP 页面 他们会给你很好的指导。

于 2013-05-11T21:49:16.007 回答