【问题标题】:bin2hex vs base64_encode for random hashed token?bin2hex vs base64_encode 用于随机散列令牌?
【发布时间】:2017-03-15 22:09:30
【问题描述】:

要为密码重置或电子邮件激活生成安全的 URL 安全哈希,以下应用程序中的 bin2hexbase64_encode 哪个功能更安全?

1.生成令牌(使用其中之一):

$token = bin2hex(openssl_random_pseudo_bytes(32));
$token = strtr(base64_encode(openssl_random_pseudo_bytes(64)), "+/=", "XXX");

2。存储在数据库中:

$token_hash = password_hash($token, PASSWORD_BCRYPT);
INSERT INTO hash_table SET token_hash='$token_hash', series='X'

3.验证令牌:

SELECT token_hash FROM hash_table WHERE series='X'
if (password_verify($hash_from_url,$token_hash)) {
  // Success
}

我注意到当 $hash_from_url 超过 72 个字符时,它不再有任何区别。

但是使用 base64 来获取 61 个不同的字符而不是使用 16 个不同的 bin2hex 会更好吗,假设我使用更多的随机字节,对于同样长的字符串,即长度为 72 个字符?

【问题讨论】:

    标签: hash passwords hex base64 password-encryption


    【解决方案1】:

    编码本身在安全性方面实际上并没有改变任何东西。

    正如您已经指出的那样,bin2hex() 将返回更长的字符串作为base64_encode() 相同的字节数,因为可能的字符基数较小。这意味着,如果给定令牌的长度,base64 编码会产生具有更多熵的令牌,因此更适合。

    如果您的令牌足够强(至少 20 个字符 a..z、A..Z、0..9),您可以使用简单的哈希函数(例如 SHA-256)而不使用加盐和密钥拉伸来代替 password_hash。这样您就可以在数据库中创建可搜索的哈希值。

    前段时间,我写了一个small class来生成一定长度的base62令牌用于密码重置,也许你想看看代码。

    【讨论】:

    • 谢谢,我认为不存储通过电子邮件发送给用户的哈希值更安全,而是存储系列标识符,然后使用 password_hash 将用户提供的哈希值与加密哈希值进行比较?为什么我想要一个可搜索的哈希?由于定时攻击,这不是不安全的吗?
    • @Niclas - 好问题。只是为了澄清,您不会将哈希发送给用户,而是链接应该包含原始令牌。定时攻击不起作用,因为您的服务器应用程序会再次计算散列并搜索此散列。哈希不允许对两个原始标记的相似性做出结论。标识符的问题是,您也必须将其存储在某个地方,并且您必须将其与链接一起发送。这允许更短的令牌(使用键拉伸存储),但 URL 由于包含标识符而增长。
    • 再次感谢,在我的示例中,我可能将单词 token 与 hash 混淆了,这让人有点困惑。我会检查你的课程,并阅读更多关于按键拉伸的信息。我对长令牌没有问题,而且我觉得它们更安全,但也许 128 个字符 base62 是矫枉过正?我将重置链接隐藏在 HTML 后面,但如果有人阅读普通版本并且 URL 中断,则可能会出现问题。但是我应该为较小的电子邮件客户端牺牲安全性吗?
    • @Niclas - 从某一点来看,延长代币不再提高安全性。如果攻击者可以每秒暴力破解 100Giga SHA256,我们仍然可以预期大约 1E17 年的随机 20 字符令牌直到他找到匹配项(一个包含 17 个零的数字)。 24 个字符是安全的。
    • stackoverflow.com/questions/1354999/… 是您的意思,通过在数据库中存储可搜索的哈希值吗?实际上我是用它来保持登录状态,但是对于重置密码 URL 是否实用?
    猜你喜欢
    • 1970-01-01
    • 2011-11-20
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-24
    • 1970-01-01
    • 2012-09-09
    相关资源
    最近更新 更多