正在使用 microtime() 生成密码重置令牌不好的做法

Posted

技术标签:

【中文标题】正在使用 microtime() 生成密码重置令牌不好的做法【英文标题】:Is using microtime() to generate password-reset tokens bad practice 【发布时间】:2013-03-09 19:01:48 【问题描述】:

php 中,我注意到一些框架使用 microtime() 函数来生成密码重置令牌,如下所示:

  $token = md5(microtime());

这是一个安全问题吗?如果攻击者能够将时钟与服务器同步到一定程度的准确度,他们就可以暴力破解令牌。 1 秒同步只需要 1,000,000 次尝试,这并不是什么疯狂的问题。

这种攻击成功的可能性有多大?是否应该使用 /dev/urandom 或 openssl_pseudo_bytes() 生成令牌? microtime() 是不好的做法吗?

【问题讨论】:

为什么不md5(microtime().mt_rand()); 【参考方案1】:

是的,这是一个安全问题!随着时间的推移生成令牌是一种非常糟糕的做法。 Burp Suite 使攻击者可以很容易地暴力破解可预测的令牌,并且基于时间的令牌非常可预测。 Burp 允许人们轻松收集令牌并对它们进行统计分析以确定熵。使用此信息,您可以轻松预测未来的令牌。

请记住,攻击者只需正确处理一次。犯错数百万次没有区别。

这是一篇关于令牌生成的有用(也是最近的)*** 帖子,可能对您有所帮助:REST Web Service authentication token implementation

【讨论】:

【参考方案2】:

应始终随机创建令牌,而不是微时间。现在提供一些额外的安全性(因为,让我们再次面对它:计算机除了计算之外什么都做不了),你会想看看 php 的例子:http://php.net/manual/de/function.srand.php 另请参阅http://php.net/manual/de/function.chr.php 以轻松创建“完全”随机字符串。这是我的做法

mt_srand((double) microtime() * 1000000);
    function random_string ($length = 16)
    
        $string = "";
        for ($n = 0; $n < count($length); $n++) $string .= chr(rand(32, 126));
        return $string;
    

【讨论】:

“令牌应始终随机创建,而不是微时间。” – 你用microtime 播种MT?顺便说一句:“Note: As of PHP 4.2.0, there is no need to seed the random number generator with srand() or mt_srand() as this is now done automatically.”【参考方案3】:

是的,它是(我认为)。 黑客可能会在 1 到 2 小时内猜出密码。 (如果服务器使用限制可以进行多少重置,黑客可以通过使用Botnet 或通过大量时间和大量试验来避免它。

如果我是你,我会添加静态盐。盐应该从配置(或其他安全的地方)加载。盐不应由服务器自己或任何人设置。它应该由真正的随机 API 生成(谷歌应该可以帮助你,但我猜 random.org 提供了一个)。 如果您无法使用该 API,那么伪盐应该会有所帮助,只要该死的人不知道服务器何时设置(或者服务器管理员有时可能会删除它,但不是自动的!)

例子:

$salt = null;
include('protectedDir/salt.php'); // Here should stand "$salt = ''"
if ($salt == null)
// Using real random api
file_put_contents('protectedDir/salt.php', '<?php \$salt = \'$salt\'; ?>)";


$resetKey = sha1(microtime() . $salt);

// 可能包含错误。未经测试。这只是一个例子,不应该通过复制和粘贴来实现。

如果黑客可以访问 php 文件('protectedDir/salt.php')“源代码”,他也应该能够看到数据库配置。这将是一个更大的问题。

【讨论】:

好主意,虽然我不确定静态盐在这种情况下是否有帮助,因为熵非常低(并且它是 100% 可预测的)。为了有效,盐需要是动态的并且非常随机。在我看来,最好让整个令牌完全随机。

以上是关于正在使用 microtime() 生成密码重置令牌不好的做法的主要内容,如果未能解决你的问题,请参考以下文章

Django密码重置生成http链接而不是https

生成重置密码令牌的最佳实践

如何在 Node.js 中正确实现“忘记/重置密码”功能? (使用一次性令牌)

使用 jwt 结构重置密码

Parse Server 上的自定义重置密码系统

身份密码重置令牌无效