简短的回答:
不,不是好盐。time()
长答案:
从我对Salt Generation和开源软件的回答中复制
什么是盐?
盐是添加到哈希算法输入中的一组固定长度的随机字节。
为什么腌制(或播种)哈希值有用?
向哈希添加随机盐可确保相同的密码将生成许多不同的哈希。盐通常与哈希函数的结果一起存储在数据库中。腌制哈希值是件好事,原因有很多:
- 腌制大大增加了预先计算的攻击(包括彩虹表)的难度/成本)
- Salting确保相同的密码不会产生相同的哈希值。这可确保您无法确定两个用户是否具有相同的密码。而且,更重要的是,您无法确定同一个人是否在不同系统中使用相同的密码。
-
盐渍增加了密码的复杂性,从而大大降低了字典和生日攻击的有效性(只有当盐与哈希分开存储时,这才是正确的)。
- 适当的腌制大大增加了预计算攻击的存储需求,直到它们不再实用。(8 个字符区分大小写的字母数字密码,16 位 salt,散列为 128 位值,将占用不到 200 EB 而不减少彩虹)。
盐没有必要是秘密的。
盐不是密钥,而是盐通过使哈希函数特定于每个实例来“工作”。使用盐渍哈希,没有一个哈希函数,而是每个可能的盐值都有一个。这可以防止攻击者攻击 N 个散列密码,而攻击成本不到攻击一个密码的 N 倍。这就是盐的要点。
“秘密盐”不是盐,它被称为“密钥”,这意味着您不再计算哈希值,而是消息身份验证代码(MAC)。计算MAC是一项棘手的业务(比简单地将密钥和值组合成哈希函数要棘手得多),而且它是一个完全不同的主题。
盐对于使用它的每个实例必须是随机的。这确保了攻击者必须单独攻击每个盐渍哈希。
如果你依靠你的盐(或盐渍算法)是秘密的,你进入了通过晦涩的安全领域(不会起作用)。最有可能的是,您没有从盐的秘密中获得额外的安全性;你只是得到温暖模糊的安全感。因此,它不会使您的系统更安全,而只会分散您对现实的注意力。
那么,为什么盐必须是随机的呢?
从技术上讲,盐应该是独一无二的。盐的要点是每个散列密码都是不同的。这意味着全世界。由于没有按需分配唯一盐的中央组织,我们必须依靠下一个最好的东西,即使用不可预测的随机生成器进行随机选择,最好是在足够大的盐空间内使碰撞变得不可能(两个实例使用相同的盐值)。
尝试从一些“大概是唯一的”数据(例如用户ID)中导出盐是很诱人的,但是由于一些令人讨厌的细节,这样的方案经常失败:
例如,如果您使用用户 ID,一些攻击不同系统的坏人可能只是汇集他们的资源并为用户 ID 1 到 50 创建预先计算的表。用户 ID 在系统范围内是唯一的,但不是全球性的。
这同样适用于用户名:每个Unix系统都有一个“根”,但世界上有很多根。“根”的彩虹表是值得的,因为它可以应用于数百万个系统。更糟糕的是,那里也有很多“bob”,许多人没有系统管理员培训:他们的密码可能很弱。
唯一性也是暂时的。有时,用户会更改其密码。对于每个新密码,必须选择一个新盐。否则,攻击者获取了旧密码的哈希值,而新密码的哈希值可能会尝试同时攻击两者。
使用从加密安全,不可预测的PRNG获得的随机盐可能是某种过度杀伤,但至少它可以证明可以保护您免受所有这些危害。这不是要阻止攻击者知道单个盐是什么,而是不要给他们一个大而胖的目标,这些目标将用于大量的潜在目标。随机选择使目标尽可能薄。
结论:
使用随机的、均匀分布的高熵盐。每当您创建新密码或更改密码时,请使用新盐。将盐与散列密码一起存储。喜欢大盐(至少10个字节,最好是16个或更多)。
盐不会把一个坏密码变成一个好密码。它只是确保攻击者至少会为他破解的每个坏密码支付字典攻击价格。
有用的来源:
stackoverflow.com:密码哈希
的非随机盐 Bruce Schneier:实用密码学(书)
Matasano安全性:足够彩虹表
usenix.org:Unix密码自1976
年以来一直使用盐 owasp.org:为什么要添加盐
openwall.com: 盐类
免责声明:
我不是安全专家。(虽然这个答案是由托马斯·波尔宁审查的)
如果任何安全专业人员发现错误,请发表评论或编辑此wiki答案。
至于什么似乎是你的随机盐
的良好来源,另请阅读:随机数生成最安全的种子是什么?
在没有专用的、基于硬件的随机生成器的情况下,获取随机数据的最佳方式是询问操作系统(在Linux上,这被称为或[两者都有优点和问题,选择你的毒药];在Windows上,调用/dev/random
/dev/urandom
CryptGenRandom()
)
如果由于某种原因您无法访问上述随机源,则可以在PHP中使用以下函数:
来自phpass v0.3的源
<?php
/**
* Generate pseudo random bits
* @copyright: public domain
* @link http://www.openwall.com/phpass/
* @param int $length number of bits to generate
* @return string A string with the hexadecimal number
* @note don't try to improve this, you will likely just ruin it
*/
function random_bits($entropy) {
$entropy /= 8;
$state = uniqid();
$str = '';
for ($i = 0; $i < $entropy; $i += 16) {
$state = md5(microtime().$state);
$str .= md5($state, true);
}
$str = unpack('H*', substr($str, 0, $entropy));
// for some weird reason, on some machines 32 bits binary data comes out as 65! hex characters!?
// so, added the substr
return substr(str_pad($str[1], $entropy*2, '0'), 0, $entropy*2);
}
?>