我想知道使用substr(md5(rand()), 0, 17);
对于密码重置链接是否足够安全?如果我要生成一个更长的字符串会使它更安全吗? MD5完全安全吗?或者我应该$token = sha1(uniqid($username, true));
?
答案 0 :(得分:3)
使用substr()
或md5()
是使用rand()
的次要因素。
使用密码重置令牌的全部意义在于它们是不可预测的,并且由于底层LCG模型,rand()
已知较弱。
最好使用系统的熵源,例如:
$rand = openssl_random_pseudo_bytes(8); // take 8 random bytes
$token = substr(md5($rand), 0, 17);
它从系统的随机源中获取字节,例如Linux上的/dev/urandom
或Windows的相应系统。
注意,如果您没有任何特定的大小限制,您也可以选择一个完整的sha1()
输出并选择16个随机字节。
此外,当您将密码重置令牌存储在数据库中时,应将其视为(临时的,有时间限制的)密码;我建议将以上令牌发送给用户,然后在将其写入数据库之前使用password_hash()
。在稍后阶段,您使用password_verify()
检查给定令牌(假设它未过期)。
答案 1 :(得分:0)
对于随机哈希,它足够安全。您的问题是碰撞,随机值上MD5的前17个字符应该足够随机,以避免它们出现在轻型项目中。
我会在uniqid()
之上选择额外熵rand()
(甚至可能mt_rand()
)。
但是,我不会使用MD5
或SHA1
来存储您的密码。
答案 2 :(得分:0)
除非你有某种有意义的长度约束,否则我没有看到使用substr()的重点。密钥越大越好。通常,以完整形式使用哈希是个好主意。如果MD5被认为是“足够安全”,那么它就已经被削减了。修剪越多,碰撞的可能性就越大。
我更喜欢使用GUID进行密码重置链接。 GUID与随机数的MD5哈希一样有效地不可预测(且安全),并且它们都是128位值。
确保使用重置令牌的到期时间戳。我通常使用24小时。
请勿使用系统时钟或任何衍生产品。您希望确保黑客无法重置其他用户的密码,同时记录时间戳,然后猜测重置令牌以生成重置URL。因此,不要直接根据系统时钟或任何其他可预测的值使用值。
您还应该对单个密码重置令牌使用失败/最大重试次数,就像常规登录一样,以限制可能的攻击次数。如果黑客知道用户标识并且正在尝试猜测密码重置URL,则应该跟踪针对给定用户标识的尝试次数作为登录尝试,并相应地锁定该帐户。最多黑客获得3次尝试,然后将帐户锁定一小时。在这种情况下,MD5的substr()仍然非常安全。