问题描述
我正在查看一些我没有自己编写的代码.该代码尝试使用 SHA512 对密码进行哈希处理,并仅使用 time()
作为盐.time()
是不是太简单了,或者这段代码安全吗?
I'm looking at some code that I have not written myself. The code tries to hash a password with SHA512 and uses just time()
as the salt. Is time()
too simple a salt for this or is this code safe?
感谢您的回答和评论.我将在这里为新读者总结:
Thanks for the answers and comments. I will sum it up here for the new readers:
- salt 对于每个用户应该是不同的,所以如果 2 个用户同时注册,他们的 salts 不会是唯一的.这是一个问题,但不是大问题.
- 但是盐不应该与用户有任何关系,所以 time() 不是一个好的盐.
- "使用随机的、均匀分布的、高熵的盐." -- 那是一口,那么什么代码可能会生成一个
随机的、均匀分布的、高熵的
盐?
- salt should be different for each user, so if 2 users register at the same time, their salts won't be unique. This is a problem, but not a big one.
- but salt shouldn't be in any way related to the user, so time() is not a good salt.
- "Use a random, evenly distributed, high entropy salt." -- That's a mouthful, so what code could possibly generate a
random, evenly distributed, high entropy
salt?
好的,那么我用一个 32 个字符长的随机字符串替换 time() 怎么样.随机字符串可以通过在一组字母字符上循环 32 次来生成.听起来好吗?
Ok, so how about I replace time() with a random string 32 char long. The random string could be generated from looping 32 times over a set of alphabet chars. Does that sound good?
推荐答案
Dictionary- 生日攻击Dictionary-Birthday attacks (This is only true if the salt is stored separate from the hash).
盐不是秘密密钥,而是通过使散列函数特定于每个实例而起作用".使用加盐散列,没有一个散列函数,而是每个可能的盐值都有一个散列函数.这可以防止攻击者以低于攻击一个密码的 N 倍的成本攻击 N 个散列密码.这就是盐的重点.
秘密盐"不是盐,它被称为密钥",这意味着您不再计算哈希,而是一个 消息验证码 (MAC).计算 MAC 是一项棘手的工作(比简单地将一个键和一个值组合到一个哈希函数中要复杂得多),而且它是一个完全不同的主题.
A salt is not a secret key, instead a salt 'works' by making the hash function specific to each instance. With salted hash, there is not one hash function, but one for every possible salt value. This prevent the attacker from attacking N hashed passwords for less than N times the cost of attacking one password. This is the point of the salt.
A "secret salt" is not a salt, it is called a "key", and it means that you are no longer computing a hash, but a Message Authentication Code (MAC). Computing MAC is tricky business (much trickier than simply slapping together a key and a value into a hash function) and it is a very different subject altogether.
盐必须是随机的,适用于每个使用它的实例.这确保了攻击者必须分别攻击每个加盐哈希.
如果你依赖你的盐(或加盐算法)是秘密的,你就进入了通过默默无闻的安全(不起作用).很可能,您无法从盐保密中获得额外的安全性;你只会得到温暖而模糊的安全感.因此,它不会让您的系统更安全,只会让您分心.
The salt must be random for every instance in which it is used. This ensures that an attacker has to attack every salted hash separately.
If you rely on your salt (or salting algorithm) being secret, you enter the realms of Security Through Obscurity (won't work). Most probably, you do not get additional security from the salt secrecy; you just get the warm fuzzy feeling of security. So instead of making your system more secure, it just distracts you from reality.
从技术上讲,盐应该是独特的.盐的要点是每个散列密码都是不同的.这意味着全球.由于没有按需分配独特盐的中央组织,我们必须依靠下一个最好的方法,即使用不可预测的随机发生器进行随机选择,最好在足够大的盐空间内使碰撞不可能发生(两个实例使用相同的盐值).
Technically, the salt should be unique. The point of the salt is to be distinct for each hashed password. This is meant worldwide. Since there is no central organization which distributes unique salts on demand, we have to rely on the next best thing, which is random selection with an unpredictable random generator, preferably within a salt space large enough to make collisions improbable (two instances using the same salt value).
尝试从一些可能是唯一的"数据(例如用户 ID)中推导出 salt 是很诱人的,但由于一些令人讨厌的细节,此类方案通常会失败:
It is tempting to try to derive a salt from some data which is "presumably unique", such as the user ID, but such schemes often fail due to some nasty details:
如果您使用例如用户 ID,一些攻击不同系统的坏人可能会集中他们的资源并为用户 ID 1 到 50 创建预先计算的表.用户 ID 是唯一的系统范围,但不是全球.
If you use for example the user ID, some bad guys, attacking distinct systems, may just pool their resources and create precomputed tables for user IDs 1 to 50. A user ID is unique system-wide but not worldwide.
这同样适用于用户名:每个 Unix 系统只有一个根",但世界上有许多根.root"的彩虹表值得付出努力,因为它可以应用于数百万个系统.更糟糕的是,还有很多bob",而且很多人没有接受过系统管理员培训:他们的密码可能很弱.
The same applies to the username: there is one "root" per Unix system, but there are many roots in the world. A rainbow table for "root" would be worth the effort, since it could be applied to millions of systems. Worse yet, there are also many "bob" out there, and many do not have sysadmin training: their passwords could be quite weak.
唯一性也是暂时的.有时,用户会更改他们的密码.对于每个新密码,必须选择一个新盐.否则,攻击者获得旧密码的哈希值和新密码的哈希值就可以同时攻击两者.
Uniqueness is also temporal. Sometimes, users change their password. For each new password, a new salt must be selected. Otherwise, an attacker obtained the hash of the old password and the hash of the new could try to attack both simultaneously.
使用从加密安全、不可预测的 PRNG 中获得的随机盐可能是某种矫枉过正,但至少它可以证明可以保护您免受所有这些危害.这不是要阻止攻击者知道单个盐是什么,而是要不给他们提供将用于大量潜在目标的大而胖的目标.随机选择使目标尽可能薄.
Using a random salt obtained from a cryptographically secure, unpredictable PRNG may be some kind of overkill, but at least it provably protects you against all those hazards. It's not about preventing the attacker from knowing what an individual salt is, it's about not giving them the big, fat target that will be used on a substantial number of potential targets. Random selection makes the targets as thin as is practical.
使用随机的、均匀分布的、高熵的盐.每当您创建新密码或更改密码时,请使用新盐.将盐与散列密码一起存储.首选大盐(至少 10 个字节,最好 16 个或更多).
Use a random, evenly distributed, high entropy salt. Use a new salt whenever you create a new password or change a password. Store the salt along with the hashed password. Favor big salts (at least 10 bytes, preferably 16 or more).
salt 不会将坏密码变成好的密码.它只是确保攻击者至少为他破解的每个错误密码支付字典攻击代价.
A salt does not turn a bad password into a good password. It just makes sure that the attacker will at least pay the dictionary attack price for each bad password he breaks.
有用的来源:
stackoverflow.com:密码哈希的非随机盐em>
Bruce Schneier:实用密码学(书籍)
Matasano 安全性:彩虹表就够了
usenix.org:Unix crypt 自 1976 年开始使用盐
owasp.org:为什么要加盐
openwall.com:盐
免责声明:
我不是安全专家.(尽管此答案已由 Thomas Pornin 审核)
如果那里的任何安全专业人员发现问题,请发表评论或编辑此 wiki 答案.
Disclaimer:
I'm not a security expert. (Although this answer was reviewed by Thomas Pornin)
If any of the security professionals out there find something wrong, please do comment or edit this wiki answer.
至于什么似乎是您的随机盐的良好来源
在没有专用的、基于硬件的随机生成器的情况下,获取随机数据的最佳方式是询问操作系统(在 Linux 上,这称为 /dev/random
或 /dev/urandom
[各有利弊,选择你的毒药];在Windows上,调用CryptGenRandom()
)
As for what seems to be a good source for your random salt
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()
)
如果由于某种原因您无法访问上述随机源,在 PHP 中您可以使用以下函数:
If for some reason you do not have access to the above mentioned sources of random, in PHP you could use the following function:
<?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);
}
?>
这篇关于time() 是好盐吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!