CSRF令牌和随机数中的熵

时间:2012-03-20 22:50:03

标签: php security zend-framework hash nonce

我正在使用Zend Framework制作一个分类广告网站(出于投资组合的目的,是的,我知道世界上还没有“另一个Craigslist克隆”的空间)。我正在尝试实现发布/编辑/删除的功能,而无需帐户。

要做到这一点,我觉得我需要在提交后生成Nonce并存储在数据库中。然后通过电子邮件发送给用户的链接,该链接发出删除的GET请求,如下所示:

  

http://www.somesite.com/post/delete/?id=123&nonce=2JDXS93JFKS8204HJTHSLDH230945HSLDF

只有用户拥有此唯一密钥或nonce,并且在提交后我会检查帖子ID下的数据库,并确保在删除之前匹配nonce。

我的问题是nonce实际上是多么安全。如果我使用Zend Framework的Zend_Form_Element_Hash,它会创建如下的哈希:

protected function _generateHash()
{
    $this->_hash = md5(
        mt_rand(1,1000000) 
        .  $this->getSalt() 
        .  $this->getName() 
        .  mt_rand(1,1000000)
    );
    $this->setValue($this->_hash);
}

在阅读mt_rand()时,one commenter said这个函数具有有限的熵。因此,如果你想创建随机字符串,它将只产生大约20亿个不同的字符串,无论长度如何字符串。如果您使用此类字符串作为会话标识符,密码等,这可能是严重的安全问题。

由于应用程序中nonce / token的生命周期,可能是用户选择删除帖子之前的几天或几周,我认为可能会有足够的时间来进行潜在的黑客攻击。

我意识到mt_rand()rand()的巨大升级,如this visual映射像素左侧rand和右侧mt_rand所示。但这够了吗?是什么让“ 20亿个不同的字符串”成为安全问题?

最终,如何增加现时/令牌/哈希的熵?

2 个答案:

答案 0 :(得分:1)

对于这种安全性,输出的时间长短不仅重要。它计算你用来创建它的随机性。

对于mt_rand(),随机源是它的种子和状态(自播种以来你使用它的次数)。更多mt_rand()次调用只会让您重新获得相同的随机源(没有新的熵)。

mt_rand()的种子只有32位(任何小于128位的密码都会让密码学家怀疑;)

具有32位熵的密钥的强度是40亿除以(大致)您将生成的密钥数量(例如,在100K使用之后,将有~1:43000的机会猜测任何有效密钥,这接近实际暴力破解)。

你正在添加盐,这使得它更强大,因为除了猜测种子攻击者也必须知道盐,所以如果盐很长,那么整体关键可能相当强大尽管“低”熵。

为了增加熵,您需要添加更多随机内容(即使稍微随机也可以,只是提供更少的位)来自不同的源,而不是mt_rand:microtime(),使用的内存量,进程ID ...或者只是使用/dev/random,它可以收集它可以获得的所有熵。

(编辑:uniqid()有弱熵,所以在这里没有帮助)

答案 1 :(得分:1)

上面用于md5()散列函数的输入的Zend散列生成代码具有1,000,000 X 1,000,000种不同的可能性。无论输入是什么,md5()都有32 ^ 16(1208925819614629174706176)可能的结果。平均而言,黑客需要向您的服务器发送500,000,000,000个请求才能猜出正确的随机数。

每分钟100次请求,大约需要3472222天才能入侵。