简短回答:
No, time()
不是好盐。
长答案:
copied from my answer to Salt Generation and open source software https://stackoverflow.com/questions/1645161/salt-generation-and-open-source-software/1645190#1645190
什么是盐?
盐是一种random添加到哈希算法的输入的固定长度的字节集。
为什么加盐(或播种)哈希有用?
向哈希值添加随机盐可确保相同的密码产生许多不同的哈希值。盐通常与哈希函数的结果一起存储在数据库中。
对哈希进行加盐处理有很多好处:
- 加盐大大增加了预计算攻击的难度/成本(包括彩虹桌 http://en.wikipedia.org/wiki/Rainbow_table#Rainbow_tables)
- 加盐可确保相同的密码不会产生相同的哈希值。
这可确保您无法确定两个用户是否具有相同的密码。和,更重要的是,您无法确定同一个人是否在不同系统上使用相同的密码。
-
Salting increases the complexity of passwords, thereby greatly decreasing the effectiveness of both Dictionary- http://en.wikipedia.org/wiki/Dictionary_attack and Birthday attacks http://en.wikipedia.org/wiki/Birthday_attack. (This is only true if the salt is stored separate from the hash).
- 适当加盐greatly增加了预计算攻击的存储需求,直至不再实用。 (8 个字符区分大小写的字母数字密码,具有 16 位盐,散列为 128 位值,将占用 exabytes http://en.wikipedia.org/wiki/Exabyte没有彩虹减少)。
盐没有必要保密。
盐不是秘密密钥,而是盐通过使哈希函数特定于每个实例来“工作”。使用加盐哈希,则没有one哈希函数,但每个可能的盐值都有一个。这可以防止攻击者进行攻击N哈希密码的时间小于N倍于攻击一个密码的成本。这就是盐的重点。
“秘密盐”不是盐,它被称为“密钥”,这意味着你不再计算哈希值,而是计算消息验证码 http://en.wikipedia.org/wiki/Message_authentication_code(苹果)。计算 MAC 是一件棘手的事情(比简单地将键和值组合成哈希函数要棘手得多),而且它完全是一个非常不同的主题。
盐必须是随机的对于使用它的每个实例。这确保攻击者必须单独攻击每个加盐哈希。
如果您依赖您的盐(或加盐算法)的秘密,那么您就进入了以下领域:通过默默无闻实现安全 http://en.wikipedia.org/wiki/Security_through_obscurity#Arguments_against(行不通)。最有可能的是,您不会从盐保密中获得额外的安全性;你只会得到温暖而模糊的安全感。因此,它不但不会让您的系统更加安全,反而会分散您对现实的注意力。
那么,为什么盐必须是随机的呢?
从技术上讲,盐应该是unique。盐的要点是每个散列密码都是不同的。这意思是全世界。由于没有中央组织可以按需分配独特的盐,因此我们必须依赖下一个最好的方法,即使用不可预测的随机生成器进行随机选择,最好是在足够大的盐空间内以使得碰撞不可能发生(两个实例使用相同的盐)盐值)。
人们很容易尝试从一些“可能是唯一的”数据(例如用户 ID)中派生出盐,但此类方案通常会因一些令人讨厌的细节而失败:
如果你使用例如用户 ID,一些攻击不同系统的坏人可能只是集中资源并为用户 ID 1 到 50 创建预先计算的表。用户 ID 是唯一的全系统但不是全世界.
这同样适用于username:每个 Unix 系统都有一个“根”,但世界上有很多根。 “root”的彩虹表是值得付出努力的,因为它可以应用于数百万个系统。更糟糕的是,还有许多“bob”,其中许多人没有接受过系统管理员培训:他们的密码可能非常弱。
唯一性也是暂时的。有时,用户会更改密码。对于每个新密码, a new salt必须被选择。否则,攻击者获得旧密码的哈希值和新密码的哈希值可能会尝试同时攻击两者。
使用从加密安全、不可预测的 PRNG 中获得的随机盐可能有点矫枉过正,但至少它provably保护您免受所有这些危险。这并不是为了阻止攻击者知道什么是个人盐是,它是关于不要给他们一个大而胖的目标,而这个目标将用于大量的潜在目标。随机选择使目标尽可能薄。
综上所述:
使用随机、均匀分布的高熵盐。每当您创建新密码或更改密码时,请使用新的盐。将盐与散列密码一起存储。喜欢大盐(至少 10 个字节,最好是 16 个或更多)。
盐不会将坏密码变成好密码。它只是确保攻击者至少要付出字典攻击的代价each他破解了错误的密码。
有用的来源:
stackoverflow.com:密码哈希值的非随机盐 https://stackoverflow.com/questions/536584/non-random-salt-for-password-hashes/536756#536756
布鲁斯·施奈尔:实用密码学 http://www.schneier.com/book-practical.html (book)
又野保安:彩虹表够了 http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
usenix.org:Unix crypt 自 1976 年起就使用 salt http://www.usenix.org/events/usenix99/provos/provos_html/node9.html
owasp.org http://www.owasp.org/: 为什么要加盐 http://www.owasp.org/index.php/Hashing_Java#Why_add_salt_.3F
openwall.com http://www.openwall.com/: Salts http://www.openwall.com/lists/john-users/2005/12/18/1
免责声明:
我不是安全专家。 (虽然这个答案是由托马斯·波宁 https://stackoverflow.com/users/254279/thomas-pornin)
如果任何安全专业人员发现错误,请发表评论或编辑此 wiki 答案。
As for what seems to be a good source for your random salt
Also read: What is the most secure seed for random number generation? https://stackoverflow.com/questions/3436376/what-is-the-most-secure-seed-for-random-number-generation/3532136#3532136
In the absence of dedicated, hardware based, random generators, the best way of obtaining random data is to ask the operating system (on Linux, this is called /dev/random
or /dev/urandom
[both have advantages and problems, choose your poison]; on Windows, call CryptGenRandom()
)
If for some reason you do not have access to the above mentioned sources of random, in PHP you could use the following function:
From the source of phpass v0.3 http://www.openwall.com/phpass/
<?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);
}
?>