为网络服务添加密码的原因
Reason for salting a password for webservice
我有一个与用户管理相关的非常基本的问题,尤其是存储散列密码。
我读了几页(比如 https://wiki.python.org/moin/Md5Passwords )。
我理解散列的方式是这样的:
- 用户提供的密码以一种方式散列(使用任何函数)。
- 没有人(包括 user/admin)能够看到密码。
- 当用户登录时 - 对他提供的字符串进行哈希处理以查看它是否与存储的哈希密码匹配。
这很清楚,但是我不确定 'salt' 在散列中的作用。
我读到 os.urandom (Python) 是很好的造好盐:
https://crackstation.net/hashing-security.htm
我不确定如何使用这个添加的 "salt"
如果我用盐和它的一种方式散列用户密码。下次用户登录时,他只知道密码,不知道盐。由此我假设为该用户生成的 "salt" 需要存储在某个地方。否则就没有意义。但另一方面,如果有人可以访问数据库,则会看到 "salt" 和散列密码。在这种情况下 "salt" 不会增加太多价值(它与散列纯密码几乎相同)。所以也许 "salt" 只是为了防止前端保护(针对蛮力)。
有人可以告诉我如何使用盐吗?我的理解对吗。我需要在某处存储 "salt" 吗?
在我发布这个问题之前,我发现了这个:
Should the Salt for a password Hash be "hashed" also?
盐的附加值是多少?
如果我编写 Web 服务,我可以在 3 次尝试失败后阻止每次登录。
前端没有人能够看到散列值。没有人可以使用暴力(这可能只是 DoS,因为 3 次失败的登录将阻止用户)。黑客将需要访问数据库并查看散列密码。但如果他有,他会看到 "salt".
Salt 用于防止黑客反转 密码散列为密码。所以这里我们假设黑客以某种方式访问了数据库。
无盐
让我们先假设没有盐的情况。在那种情况下,table 看起来像:
user | md5 password (first 6 chars)
-------------------------------
1 | 1932ff
2 | d3b073
(我们这里把情况说得比实际情况要简单)
黑客当然想知道d3b073
和1932ff
背后的密码是什么。哈希函数是 单向 从某种意义上说,我们可以非常快速地对密码进行哈希处理,但是对其进行解散处理(鉴于它是一个很好的散列函数)会花费很长时间,在猜测一个大量密码。
所以想轻松找回d3b073
背后的可能密码的希望不大。但是我们可以轻松找到 100'000 个最流行密码的列表,并计算所有这些密码的 MD5 哈希值。这样的列表可能如下所示:
password | md5 (first 6 characters)
--------------------------------------------
foo | d3b073
bar | c157a7
显然用户 2
使用了 foo
作为密码。我们不知道用户 1
的密码(但我们知道它不是 foo
或 bar
)。
现在的重点是,我们可以构造这样的table一次,然后用它来破解全部个密码所有 用户。为 100'000 个密码构造这样的 table 可能需要几个小时,但随后我们可以轻松检索所有密码。所以黑客可以构建(或下载)这样的 table(有更有效的方法,例如 rainbow tables),然后每次都使用它he/she 入侵一个网站,然后获取所有用户的密码。
加盐
如果我们使用盐腌,table 可能看起来像这样:
user | salt | hashed password
-------------------------------
1 | a91f40 | 1a604e
2 | c2a67c | b36232
所以这里如果用户2
的密码是foo
,那么我们计算fooc2a67c
的散列(或者我们用另一种方式结合盐和密码)和将其存储到数据库中。
关键是很难猜出密码,因为 b36232
不是 foo
的散列,而是 fooc2a67c
的散列,并且盐通常是某种东西(伪)-随机的。我们当然可以再次构造最流行的 100'000 个密码,并附加 salt c2a67c
,但是由于我们无法提前知道 salt,因此我们无法创建此table只有一次。即使我们很幸运并且已经为 salt c2a67c
构建了 table,它也不会帮助我们破解用户 1
的密码,因为用户 1 有不同的 salt.
因此,解决此问题的唯一方法是为每个用户构建反向哈希查找 table。由于构建这样的 table 一次通常非常昂贵,因此要为 每个 用户计算这样的 table 并不容易。
我们当然可以决定计算所有可能盐的所有哈希值,例如:
password | md5 (first 6 characters)
---------------------------------------------
foo000000 | 367390
foo000001 | eca8ea
foo000002 | 6eb7bf
foo000003 | 7906b1
foo000004 | 0e9f0c
foo000005 | 0bfb11
... | ...
但是如您所见,这样的 table 的大小会增长到巨大的大小。此外,这将需要数千年的时间。即使我们只添加一个十六进制字符作为盐,table 的大小也会缩放 16 倍。是的,有一些技术可以减少 table 的时间和 space,但是通过增加 "password space",破解密码的问题肯定会更难。此外,盐通常是大量的字符(或字节)长,这使得它比仅仅 16 倍更难。
基本上盐是一种扩大密码的方法space。即使您在两个网站上输入完全相同的密码,网站的 personal salt 将(几乎可以肯定)是唯一的,因此哈希值也将是唯一的。
我有一个与用户管理相关的非常基本的问题,尤其是存储散列密码。 我读了几页(比如 https://wiki.python.org/moin/Md5Passwords )。 我理解散列的方式是这样的:
- 用户提供的密码以一种方式散列(使用任何函数)。
- 没有人(包括 user/admin)能够看到密码。
- 当用户登录时 - 对他提供的字符串进行哈希处理以查看它是否与存储的哈希密码匹配。
这很清楚,但是我不确定 'salt' 在散列中的作用。 我读到 os.urandom (Python) 是很好的造好盐: https://crackstation.net/hashing-security.htm
我不确定如何使用这个添加的 "salt" 如果我用盐和它的一种方式散列用户密码。下次用户登录时,他只知道密码,不知道盐。由此我假设为该用户生成的 "salt" 需要存储在某个地方。否则就没有意义。但另一方面,如果有人可以访问数据库,则会看到 "salt" 和散列密码。在这种情况下 "salt" 不会增加太多价值(它与散列纯密码几乎相同)。所以也许 "salt" 只是为了防止前端保护(针对蛮力)。
有人可以告诉我如何使用盐吗?我的理解对吗。我需要在某处存储 "salt" 吗?
在我发布这个问题之前,我发现了这个: Should the Salt for a password Hash be "hashed" also?
盐的附加值是多少? 如果我编写 Web 服务,我可以在 3 次尝试失败后阻止每次登录。 前端没有人能够看到散列值。没有人可以使用暴力(这可能只是 DoS,因为 3 次失败的登录将阻止用户)。黑客将需要访问数据库并查看散列密码。但如果他有,他会看到 "salt".
Salt 用于防止黑客反转 密码散列为密码。所以这里我们假设黑客以某种方式访问了数据库。
无盐
让我们先假设没有盐的情况。在那种情况下,table 看起来像:
user | md5 password (first 6 chars)
-------------------------------
1 | 1932ff
2 | d3b073
(我们这里把情况说得比实际情况要简单)
黑客当然想知道d3b073
和1932ff
背后的密码是什么。哈希函数是 单向 从某种意义上说,我们可以非常快速地对密码进行哈希处理,但是对其进行解散处理(鉴于它是一个很好的散列函数)会花费很长时间,在猜测一个大量密码。
所以想轻松找回d3b073
背后的可能密码的希望不大。但是我们可以轻松找到 100'000 个最流行密码的列表,并计算所有这些密码的 MD5 哈希值。这样的列表可能如下所示:
password | md5 (first 6 characters)
--------------------------------------------
foo | d3b073
bar | c157a7
显然用户 2
使用了 foo
作为密码。我们不知道用户 1
的密码(但我们知道它不是 foo
或 bar
)。
现在的重点是,我们可以构造这样的table一次,然后用它来破解全部个密码所有 用户。为 100'000 个密码构造这样的 table 可能需要几个小时,但随后我们可以轻松检索所有密码。所以黑客可以构建(或下载)这样的 table(有更有效的方法,例如 rainbow tables),然后每次都使用它he/she 入侵一个网站,然后获取所有用户的密码。
加盐
如果我们使用盐腌,table 可能看起来像这样:
user | salt | hashed password
-------------------------------
1 | a91f40 | 1a604e
2 | c2a67c | b36232
所以这里如果用户2
的密码是foo
,那么我们计算fooc2a67c
的散列(或者我们用另一种方式结合盐和密码)和将其存储到数据库中。
关键是很难猜出密码,因为 b36232
不是 foo
的散列,而是 fooc2a67c
的散列,并且盐通常是某种东西(伪)-随机的。我们当然可以再次构造最流行的 100'000 个密码,并附加 salt c2a67c
,但是由于我们无法提前知道 salt,因此我们无法创建此table只有一次。即使我们很幸运并且已经为 salt c2a67c
构建了 table,它也不会帮助我们破解用户 1
的密码,因为用户 1 有不同的 salt.
因此,解决此问题的唯一方法是为每个用户构建反向哈希查找 table。由于构建这样的 table 一次通常非常昂贵,因此要为 每个 用户计算这样的 table 并不容易。
我们当然可以决定计算所有可能盐的所有哈希值,例如:
password | md5 (first 6 characters)
---------------------------------------------
foo000000 | 367390
foo000001 | eca8ea
foo000002 | 6eb7bf
foo000003 | 7906b1
foo000004 | 0e9f0c
foo000005 | 0bfb11
... | ...
但是如您所见,这样的 table 的大小会增长到巨大的大小。此外,这将需要数千年的时间。即使我们只添加一个十六进制字符作为盐,table 的大小也会缩放 16 倍。是的,有一些技术可以减少 table 的时间和 space,但是通过增加 "password space",破解密码的问题肯定会更难。此外,盐通常是大量的字符(或字节)长,这使得它比仅仅 16 倍更难。
基本上盐是一种扩大密码的方法space。即使您在两个网站上输入完全相同的密码,网站的 personal salt 将(几乎可以肯定)是唯一的,因此哈希值也将是唯一的。