PHP CSRF攻击

时间:2013-05-11 21:42:01

标签: php forms security token csrf

我想知道这段代码是否足以阻止对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>

感谢。

3 个答案:

答案 0 :(得分:2)

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

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

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

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

除了这个小问题,我在其中看不到任何CSRF漏洞。该代码看起来会起作用。

答案 1 :(得分:1)

在我支持的产品上,我会说“不”。您的随机数生成器基于可预测的rand()。此外,看起来随机数非常短 - 它需要足够长,以至于在会话有效期内不能强制执行 - 也不能破解任何多个活动会话的CSRF令牌。

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

答案 2 :(得分:1)

我认为这足以达到既定目的。

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

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

然而,这33个字节不提供264位的熵,但方式更少:

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

这总计近81个未知位。为了强制这一点,人们平均需要2个 81 /2≈1.2·10 24 猜测,这些猜测会在散列时产生给定的令牌。要处理的数据大约为8·10 13 TB。使用今天的计算机,你应该可以在大约5.215·10 17 秒内运行它。

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