bcrypt 散列与比较用户登录
bcrypt hashing vs comparing on user login
首先,对于这个问题,我深表歉意。我知道有很多类似的明显问题询问如何在 X 应用程序中实现 bcrypt,但在这里我要问两种策略。
我最近刚刚在用户登录中实现了 bcrypt。基本上:
- 用户将凭据发送到我的其余 api 服务器
- I bcrypt.hash 给定的密码并使用简单的 where 子句将其与数据库进行比较,如下所示:
WHERE mail = $mail and password = $my_just_hashed_password
- 如果我在数据库中找到一个用户,我假设给定的密码是正确的。否则,我拒绝请求。
这与首先从给定的唯一邮件中选择用户,然后 bcrypt.compare 给定的密码和从数据库中散列的密码几乎相同。
我的问题是,哪个更好?我知道 bcrypt 哈希函数旨在用于安全地存储敏感数据,但为什么不使用它来验证用户呢?
当您使用 bcrypt 正确散列密码时,您会在密码后附加一个至少包含 16 个随机字符的字符串,然后 运行 整个密码会通过 bcrypt 数千次。完成哈希算法至少需要四分之一秒。然后你存储随机数。字符串,称为盐,以及散列密码。
要验证密码,您可以从存储的密码散列中提取盐,然后将要验证的密码与盐一起散列。两个哈希值必须匹配。
由于盐的存在,您永远无法将一个哈希值与另一个哈希值进行比较并期望它们相等。
请阅读此内容。 https://en.m.wikipedia.org/wiki/Bcrypt#Description
为什么这么复杂?因为 cybercreeps。因为 cybercreeps 有时可以窃取大型网络应用程序的 users
table。他们窃取用户名和电子邮件已经够糟糕了,但我们不希望他们也窃取密码。参见 Adobe。参见 Ashley Madison。
如果没有随机盐,攻击者可能会构造查找 tables 来帮助从哈希猜测密码:如今 RAM 很便宜。随机盐意味着查找 table 不再可行。您知道某些用户会选择 654321
作为密码,我们不希望攻击者能够搜索所有密码以查找该密码和其他 common 密码的哈希版本。
此外,我们使用 Blowfish 密码算法,因为它比 MD-5 和各种 SHA 哈希算法慢。这很好:我们希望攻击者面对缓慢的散列算法,因此他们无法每秒猜出数千个密码。使用 bcrypt 蛮力猜测密码非常耗时。
最后,使用经过仔细验证的加密算法是信息安全的原则。自己动手是不明智的。假设 cybercreeps 比你更聪明,更有动力,你会更有安全感。
请不要使用您描述的方法。
我将针对已批准的答案提供替代答案,重点是安全性...
由于电子邮件是唯一的,我会首先单独根据电子邮件找到用户,从检索到的用户那里获取密码,然后使用 bcrypt
进行比较。如果电子邮件存在,但密码不匹配,则可能存在暴力攻击,您可能需要记录这些失败的尝试,以便您可以锁定帐户或添加验证码以减缓 down/prevent 攻击.
这有什么不同
原始解决方案
- 从电子邮件和散列密码中获取用户
- 如果凭据正确,很好,用户可以登录。这里没有问题
- 如果找不到用户,是电子邮件或密码不正确吗?仅凭这一查询无法知道。
- 潜在的攻击者可以通过在输入的电子邮件上尝试不同的密码来继续尝试访问潜在的帐户。
替代解决方案
- 仅从电子邮件中获取用户
- 如果用户存在,将数据库中的散列用户密码与输入凭据的散列密码进行比较(使用 bcrypt
compare
)。
- 如果密码不正确,请在另一个table(
USER_FAILED_LOGINS
)中登录,3次尝试失败后,添加一些安全措施,例如验证码。
- 如果密码正确,很好,让用户登录。
您当然可以使用原来的解决方案,如果凭据不正确,则再进行一次查询,以确定电子邮件是否存在,并在此时实施安全措施。请警惕这些类型的攻击并加以防范。另外,请确保您在 SQL.
中使用准备好的语句
首先,对于这个问题,我深表歉意。我知道有很多类似的明显问题询问如何在 X 应用程序中实现 bcrypt,但在这里我要问两种策略。
我最近刚刚在用户登录中实现了 bcrypt。基本上:
- 用户将凭据发送到我的其余 api 服务器
- I bcrypt.hash 给定的密码并使用简单的 where 子句将其与数据库进行比较,如下所示:
WHERE mail = $mail and password = $my_just_hashed_password
- 如果我在数据库中找到一个用户,我假设给定的密码是正确的。否则,我拒绝请求。
这与首先从给定的唯一邮件中选择用户,然后 bcrypt.compare 给定的密码和从数据库中散列的密码几乎相同。
我的问题是,哪个更好?我知道 bcrypt 哈希函数旨在用于安全地存储敏感数据,但为什么不使用它来验证用户呢?
当您使用 bcrypt 正确散列密码时,您会在密码后附加一个至少包含 16 个随机字符的字符串,然后 运行 整个密码会通过 bcrypt 数千次。完成哈希算法至少需要四分之一秒。然后你存储随机数。字符串,称为盐,以及散列密码。
要验证密码,您可以从存储的密码散列中提取盐,然后将要验证的密码与盐一起散列。两个哈希值必须匹配。
由于盐的存在,您永远无法将一个哈希值与另一个哈希值进行比较并期望它们相等。
请阅读此内容。 https://en.m.wikipedia.org/wiki/Bcrypt#Description
为什么这么复杂?因为 cybercreeps。因为 cybercreeps 有时可以窃取大型网络应用程序的 users
table。他们窃取用户名和电子邮件已经够糟糕了,但我们不希望他们也窃取密码。参见 Adobe。参见 Ashley Madison。
如果没有随机盐,攻击者可能会构造查找 tables 来帮助从哈希猜测密码:如今 RAM 很便宜。随机盐意味着查找 table 不再可行。您知道某些用户会选择 654321
作为密码,我们不希望攻击者能够搜索所有密码以查找该密码和其他 common 密码的哈希版本。
此外,我们使用 Blowfish 密码算法,因为它比 MD-5 和各种 SHA 哈希算法慢。这很好:我们希望攻击者面对缓慢的散列算法,因此他们无法每秒猜出数千个密码。使用 bcrypt 蛮力猜测密码非常耗时。
最后,使用经过仔细验证的加密算法是信息安全的原则。自己动手是不明智的。假设 cybercreeps 比你更聪明,更有动力,你会更有安全感。
请不要使用您描述的方法。
我将针对已批准的答案提供替代答案,重点是安全性...
由于电子邮件是唯一的,我会首先单独根据电子邮件找到用户,从检索到的用户那里获取密码,然后使用 bcrypt
进行比较。如果电子邮件存在,但密码不匹配,则可能存在暴力攻击,您可能需要记录这些失败的尝试,以便您可以锁定帐户或添加验证码以减缓 down/prevent 攻击.
这有什么不同
原始解决方案
- 从电子邮件和散列密码中获取用户
- 如果凭据正确,很好,用户可以登录。这里没有问题
- 如果找不到用户,是电子邮件或密码不正确吗?仅凭这一查询无法知道。
- 潜在的攻击者可以通过在输入的电子邮件上尝试不同的密码来继续尝试访问潜在的帐户。
替代解决方案
- 仅从电子邮件中获取用户
- 如果用户存在,将数据库中的散列用户密码与输入凭据的散列密码进行比较(使用 bcrypt
compare
)。 - 如果密码不正确,请在另一个table(
USER_FAILED_LOGINS
)中登录,3次尝试失败后,添加一些安全措施,例如验证码。 - 如果密码正确,很好,让用户登录。
您当然可以使用原来的解决方案,如果凭据不正确,则再进行一次查询,以确定电子邮件是否存在,并在此时实施安全措施。请警惕这些类型的攻击并加以防范。另外,请确保您在 SQL.
中使用准备好的语句