检查了很多关于StackOver上的加密和散列的教程和指南,我现在明白了它们之间的区别。 我们需要解密时加密。你不要哈希(例如:密码)。
但我今天的问题是,用于生成随机唯一令牌。很多人建议使用base64_encode(rand_bytes(32));因为它会产生一个带有随机字节/字母的安全密码id,因此需要很长时间才能被强力破解(需要预测)。
但是当你,例如,hash_hmac或crypt这个id会让它变弱吗? 如果是这样,使用mt_rand或random_bytes无关紧要,因为它会生成其他字母/ id。所以你们推荐什么?
另外,crypt是否比hash_hmac更好用于散列?
最后一个问题,由于blowfish有一个非常强大的哈希算法,我是否需要存储我的PHPSESSID或CSRF令牌,或者只是普通的random_bytes?
请大家,向我提供有关这些问题或文档的详细信息。 抱歉我缺乏信息和经验不足,我是PHP编码的新手,谢谢!
编辑:我在SO上看过一些指南,并没有涵盖我的所有问题,所以我需要2017年的详细信息,而不是10年前的帖子,其中md5是最好的......等。答案 0 :(得分:2)
当您只想要无法预测的令牌时,请使用random_bytes(32)
。 只要您保持令牌秘密,就没有理由改变结果这个功能。
但是你问了很多具体的问题,所以我会尽力回答:
crypt()
该ID会使其变弱时?这取决于HMAC或crypt例程。当您生成32个字节的随机数据,然后使用函数将大小减小到16个字节时,安全性将减半。但是,如果使用具有至少32个字节输出的加密安全函数,则不会降低安全性。现在我这样说,因为 crypt()
不是加密安全功能。 在对密码进行散列处理时,请改为使用password_hash()
。
mt_rand
和使用random_bytes
? 是的,将重要。 mt_rand()
使用Mersenne Twister随机数生成器。这些都不安全。这意味着攻击者可以使用令牌值来猜测其他令牌。在mt_rand()
的情况下,这通常很容易。如果您需要令牌是安全的(身份验证令牌,会话cookie,CSRF令牌,可能无法枚举的ID等),请使用random_bytes
。另外,如果您不确定,请使用random_bytes
。
不。 Crypt已弃用,您不应使用它。需要消息验证代码时使用HMAC(例如密码重置URL)。对于密码哈希,请使用password_hash
。
random_bytes
存储?只需使用random_bytes
即可。随机数据已经是随机的,不需要再次随机化。至少,只要你保密这些代币并在它们泄露时立即撤销它们。
答案 1 :(得分:2)
散列不能使你的标记更强或更随机,没有办法增加真正随机标记的熵或改进它。否则就会改进它。
散列令牌的唯一时刻是有道理的,就是它存储在会话/数据库中时(客户端总是应该获取原始令牌)。在数据库中存储哈希将在数据被盗的情况下保护令牌(SQL注入)。
与“弱”用户密码相比,“强”随机令牌无法成功强制执行,因此不需要进行腌制和键拉伸。可以使用简单的快速哈希函数,如SHA-256,它可以搜索哈希值。当客户端发出请求时,可以再次对原始令牌进行哈希处理,并搜索存储的哈希值。
答案 2 :(得分:-1)
@martinstoeckli兄弟,你太棒了,当你深刻解释一切时,我理解你所描述的一切。为了确保我清楚,请检查我的代码!
1-)没有哈希值且没有存储在像CSFR令牌这样的数据库中的随机令牌
$random_code = base64_encode(random_bytes(32)); //without hashing
2-)记住我 - 客户端将拥有random_code,并且在数据库中,我存储了哈希令牌。
remember_me的例子
$random_code = base64_encode(random_bytes(32));
$token = hash_hmac('sha256', ($random_code . $username) , $random_code);
$token = hash_hmac('sha256', $random_code , $token);
setcookie("remember", $username . "|" . $random_code, time()+(60 * 60 * 24 * 7), "/", "", 1, 1); //1 week