Salt Generation 和开源软件

发布于 2024-08-09 13:07:23 字数 204 浏览 3 评论 0原文

据我了解,生成盐的最佳实践是使用源代码中存储的一些神秘公式(甚至魔术常数)。

我正在开发一个计划作为开源发布的项目,但问题是源代码带来了生成盐的秘密公式,因此能够在我们的网站上运行彩虹表攻击。

我认为很多人在我之前已经考虑过这个问题,我想知道最佳实践是什么。在我看来,如果代码是开源的,那么盐根本没有意义,因为盐可以很容易地进行逆向工程。

想法?

As I understand it, the best practice for generating salts is to use some cryptic formula (or even magic constant) stored in your source code.

I'm working on a project that we plan on releasing as open source, but the problem is that with the source comes the secret formula for generating salts, and therefore the ability to run rainbow table attacks on our site.

I figure that lots of people have contemplated this problem before me, and I'm wondering what the best practice is. It seems to me that there is no point having a salt at all if the code is open source, because salts can be easily reverse-engineered.

Thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦里泪两行 2024-08-16 13:07:23

由于有关加盐散列的问题经常出现,并且对该主题似乎存在相当大的困惑,因此我扩展了这个答案。

什么是盐?

salt 是添加到哈希算法输入的固定长度的随机字节集。

为什么加盐(或播种)哈希有用?

向哈希值添加随机盐可确保相同的密码会产生许多不同的哈希值。盐通常与哈希函数的结果一起存储在数据库中。
加盐哈希有很多好处:

  1. 加盐大大增加了预计算攻击的难度/成本(包括 彩虹表
  2. 加盐可确保相同的密码不会产生相同的哈希值。
    这可确保您无法确定两个用户是否具有相同的密码。而且,更重要的是,您无法确定同一个人是否在不同系统上使用相同的密码。
  3. 加盐会增加密码的复杂性,从而大大降低密码的有效性字典-生日攻击 (仅当盐与散列分开存储时,这才是正确的。
  4. 适当的加盐大大增加了预计算攻击的存储需求,直到它们不再实用的程度。 (8 个字符区分大小写的字母数字密码,具有 16 位盐,哈希为 128 位值,将占用 略低于 200 艾字节< /a> 没有彩虹减少)。

盐没有必要保密。

盐不是秘密密钥,而是盐通过使哈希函数特定于每个实例来“工作”。对于加盐哈希,不存在一个哈希函数,而是针对每个可能的盐值都有一个哈希函数。这可以防止攻击者攻击 N 个哈希密码,而成本却低于攻击一个密码的 N 倍。这就是盐的重点。
“秘密盐”不是盐,它被称为“密钥”,这意味着您不再计算哈希值,而是计算消息验证码 (MAC)。计算 MAC 是一件棘手的事情(比简单地将键和值组合成哈希函数要棘手得多),而且它完全是一个非常不同的主题。

对于每个使用它的实例,盐必须是随机的。这确保攻击者必须单独攻击每个加盐哈希。
如果您依赖盐(或加盐算法)的保密性,那么您就进入了通过模糊实现安全性< /a> (不起作用)。最有可能的是,您不会从盐保密中获得额外的安全性;你只会得到温暖而模糊的安全感。因此,它不但不会让您的系统更加安全,反而会分散您对现实的注意力。

那么,为什么盐必须是随机的?

从技术上讲,盐应该是唯一的。盐的要点是每个散列密码都是不同的。这意味着全世界。由于没有中央组织可以按需分配独特的盐,因此我们必须依赖下一个最好的方法,即使用不可预测的随机生成器进行随机选择,最好是在足够大的盐空间内以使得碰撞不可能发生(两个实例使用相同的盐)盐值)。

尝试从某些“可能是唯一的”数据(例如用户 ID)中派生盐是很诱人的,但此类方案通常会由于一些令人讨厌的细节而失败:

  1. 如果您使用例如用户 ID ,一些攻击不同系统的坏人可能只是集中资源并为用户 ID 1 到 50 创建预先计算的表。用户 ID 在系统范围内是唯一的,但在全球范围内不是唯一的。

  2. 这同样适用于用户名:每个 Unix 系统都有一个“root”,但世界上有很多个 root。 “root”的彩虹表是值得付出努力的,因为它可以应用于数百万个系统。更糟糕的是,还有许多“bob”,其中许多人没有接受过系统管理员培训:他们的密码可能非常弱。

  3. 唯一性也是暂时的。有时,用户会更改密码。对于每个新密码,必须选择一个新盐。否则,攻击者获得旧密码的哈希值和新密码的哈希值可能会尝试同时攻击两者。

使用从加密安全、不可预测的 PRNG 中获得的随机盐可能有点矫枉过正,但至少它可证明可以保护您免受所有这些危险。这并不是要阻止攻击者知道个人盐是什么,而是不要给他们提供将用于大量潜在目标的大而胖的目标。随机选择使目标尽可能薄。

结论:

使用随机、均匀分布的高熵盐。每当您创建新密码或更改密码时,请使用新的盐。将盐与散列密码一起存储。喜欢大盐(至少 10 个字节,最好是 16 个或更多)。

盐不会将坏密码变成好密码。它只是确保攻击者至少为他破解的每个坏密码付出字典攻击的代价。

有用的来源:
stackoverflow.com:密码哈希值的非随机盐
Bruce Schneier:实用密码学(书)
Matasano 安全性:彩虹表就够了
usenix.org:Unix crypt 自 1976 年起就使用盐
owasp.org为什么要加盐
openwall.com

免责声明:
我不是安全专家。 (尽管此答案已由 Thomas Pornin 审阅)
如果任何安全专业人士发现问题,请发表评论或编辑此 wiki 答案。

Since questions about salting hashes come along on a quite regular basis and there seems to be quite some confusion about the subject, I extended this answer.

What is a salt?

A salt is a random set of bytes of a fixed length that is added to the input of a hash algorithm.

Why is salting (or seeding) a hash useful?

Adding a random salt to a hash ensures that the same password will produce many different hashes. The salt is usually stored in the database, together with the result of the hash function.
Salting a hash is good for a number of reasons:

  1. Salting greatly increases the difficulty/cost of precomputated attacks (including rainbow tables)
  2. Salting makes sure that the same password does not result in the same hash.
    This makes sure you cannot determine if two users have the same password. And, even more important, you cannot determine if the same person uses the same password across different systems.
  3. Salting increases the complexity of passwords, thereby greatly decreasing the effectiveness of both Dictionary- and Birthday attacks. (This is only true if the salt is stored separate from the hash).
  4. Proper salting greatly increases the storage need for precomputation attacks, up to the point where they are no longer practical. (8 character case-sensitive alpha-numeric passwords with 16 bit salt, hashed to a 128 bit value, would take up just under 200 exabytes without rainbow reduction).

There is no need for the salt to be secret.

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.

So, why does the salt have to be random?

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).

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:

  1. 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.

  2. 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.

  3. 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.

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.

In conclusion:

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).

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.

Usefull sources:
stackoverflow.com: Non-random salt for password hashes
Bruce Schneier: Practical Cryptography (book)
Matasano Security: Enough with the Rainbow Tables
usenix.org: Unix crypt used salt since 1976
owasp.org: Why add salt
openwall.com: Salts

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.

渡你暖光 2024-08-16 13:07:23

实际上,每个条目的盐都需要是唯一的。即使攻击者可以计算出盐是什么,这也会使彩虹表的创建变得极其困难。这是因为盐是在对密码进行哈希处理之前添加到密码中的,因此它有效地添加了彩虹表必须包含的条目总数,以列出密码字段的所有可能值。

Really salts just need to be unique for each entry. Even if the attacker can calculate what the salt is, it makes the rainbow table extremely difficult to create. This is because the salt is added to the password before it is hashed, so it effectively adds to the total number of entries the rainbow table must contain to have a list of all possible values for a password field.

帅的被狗咬 2024-08-16 13:07:23

自从 Unix 流行以来,存储密码的正确方法是附加一个随机值(盐)并对其进行哈希处理。将盐保存在以后可以拿到的地方,但又希望坏人不会得到它。

这有一些好的效果。首先,坏人不能只列出预期的密码(例如“Password1”),将它们散列到彩虹表中,然后遍历您的密码文件寻找匹配项。如果你有一个好的两字节盐,他们必须为每个预期的密码生成 65,536 个值,这使得彩虹表的实用性大大降低。其次,如果您可以防止坏人查看您的密码文件,那么计算可能的值就会变得更加困难。第三,您使坏人无法确定某个人是否在不同网站上使用相同的密码。

为此,您需要生成随机盐。这应该以统一的概率生成所需范围内的每个数字。这并不难;一个简单的线性同余随机数生成器就可以了。

如果您需要进行复杂的计算来制作盐,那么您就做错了。如果您根据密码计算它,那么您就大错特错了。在这种情况下,您所做的只是使哈希复杂化,而不是在功能上添加任何盐。

没有一个擅长安全的人会依赖隐藏算法。现代密码学基于经过广泛测试的算法,并且为了进行广泛测试,它们必须众所周知。一般来说,人们发现使用标准算法比使用自己的算法并希望它是好的更安全。无论代码是否开源,坏人仍然有可能分析程序的功能。

Since Unix became popular, the right way to store a password has been to append a random value (the salt) and hash it. Save the salt away where you can get to it later, but where you hope the bad guys won't get it.

This has some good effects. First, the bad guys can't just make a list of expected passwords like "Password1", hash them into a rainbow table, and go through your password file looking for matches. If you've got a good two-byte salt, they have to generate 65,536 values for each expected password, and that makes the rainbow table a lot less practical. Second, if you can keep the salt from the bad guys who are looking at your password file, you've made it much harder to calculate possible values. Third, you've made it impossible for the bad guys to determine if a given person uses the same password on different sites.

In order to do this, you generate a random salt. This should generate every number in the desired range with uniform probability. This isn't difficult; a simple linear congruential random number generator will do nicely.

If you've got complicated calculations to make the salt, you're doing it wrong. If you calculate it based on the password, you're doing it WAY wrong. In that case, all you're doing is complicating the hash, and not functionally adding any salt.

Nobody good at security would rely on concealing an algorithm. Modern cryptography is based on algorithms that have been extensively tested, and in order to be extensively tested they have to be well known. Generally, it's been found to be safer to use standard algorithms rather than rolling one's own and hoping it's good. It doesn't matter if the code is open source or not, it's still often possible for the bad guys to analyze what a program does.

枕梦 2024-08-16 13:07:23

您可以在运行时为每个记录生成随机盐。例如,假设您将散列用户密码存储在数据库中。您可以在运行时生成一个由小写和大写字母数字字符组成的 8 个字符的随机字符串,将其添加到密码前面,对该字符串进行哈希处理,然后将其存储在数据库中。由于有 628 种可能的盐,生成彩虹表(针对每种可能的盐)将非常昂贵;由于您为每个密码记录使用唯一的盐,即使攻击者生成了几个匹配的彩虹表,他仍然无法破解每个密码。

您可以根据您的安全需求更改盐生成的参数;例如,您可以使用更长的盐,或者可以生成也包含标点符号的随机字符串,以增加可能的盐的数量。

You can just generate a random salt for each record at runtime. For example, say you're storing hashed user passwords in a database. You can generate an 8-character random string of lower- and uppercase alphanumeric characters at runtime, prepend that to the password, hash that string, and store it in the database. Since there are 628 possible salts, generating rainbow tables (for every possible salt) will be prohibitively expensive; and since you're using a unique salt for each password record, even if an attacker has generated a couple matching rainbow tables, he still won't be able to crack every password.

You can change the parameters of your salt generation based on your security needs; for example, you could use a longer salt, or you could generate a random string that also contains punctuation marks, to increase the number of possible salts.

﹎☆浅夏丿初晴 2024-08-16 13:07:23

使用随机函数生成器生成盐,并将其存储在数据库中,每行生成一个盐,并将其存储在数据库中。

我喜欢 django-registration 中如何生成盐。参考: http://bitbucket.org/ ubernostrum/django-registration/src/tip/registration/models.py#cl-85

salt = sha_constructor(str(random.random())).hexdigest()[:5]
activation_key = sha_constructor(salt+user.username).hexdigest()
return self.create(user=user,
           activation_key=activation_key)

他使用随机数生成的 sha 和用户名的组合来生成哈希。

本身就以坚不可摧而闻名。添加多个维度来生成盐本身,具有随机数、sha 和用户特定组件,您拥有牢不可破的安全性!

Use a random function generator to generate the salt, and store it in the database, make salt one per row, and store it in the database.

I like how salt is generated in django-registration. Reference: http://bitbucket.org/ubernostrum/django-registration/src/tip/registration/models.py#cl-85

salt = sha_constructor(str(random.random())).hexdigest()[:5]
activation_key = sha_constructor(salt+user.username).hexdigest()
return self.create(user=user,
           activation_key=activation_key)

He uses a combination of sha generated by a random number and the username to generate a hash.

Sha itself is well known for being strong and unbreakable. Add multiple dimensions to generate the salt itself, with random number, sha and the user specific component, you have unbreakable security!

谁对谁错谁最难过 2024-08-16 13:07:23

对于桌面应用程序加密数据并将其发送到远程服务器的情况,您如何考虑每次使用不同的盐?

使用 PKCS#5 和用户密码,需要盐来生成加密密钥,以加密数据。我知道在桌面应用程序中将盐硬编码(混淆)不是一个好主意。

如果远程服务器永远不知道用户的密码,是否可以每次使用不同的盐?如果用户在另一台计算机上使用桌面应用程序,如果他没有密钥(没有硬编码在软件中),如何解密远程服务器上的数据?

In the case of a desktop application that encrypts data and send it on a remote server, how do you consider using a different salt each time?

Using PKCS#5 with the user's password, it needs a salt to generate an encryption key, to encrypt the data. I know that keep the salt hardcoded (obfuscated) in the desktop application is not a good idea.

If the remote server must NEVER know the user's password, is it possible to user different salt each time? If the user use the desktop application on another computer, how will it be able to decrypt the data on the remote server if he does not have the key (it is not hardcoded in the software) ?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文