当密码未以纯文本形式存储在数据库中时,如何验证用户?

How users are verified when passwords are NOT stored as plain text in the database?

我知道将密码以明文形式存储在数据库中是不好的,因为如果黑客获得了对服务器数据库的访问权限,所有用户名和密码将完全暴露?因此,原始密码通过哈希函数传递,然后以相同长度的一系列不可理解的字符存储在数据库中。这对安全来说是件好事。

但是...服务器如何验证用户是否输入了正确的密码?由于用户以原始形式输入密码(例如:whoami、ilovecomputer...),但服务器将它们存储在“散列”形式下(例如:234203409803249580980gfdg41cdvd4、jknegnergiuhiuhdni4584234dfgbn4j...)。如何匹配用户输入的密码和服务器存储的密码?

H为密码散列函数。这些函数中的一个简单 属性 是它们是确定性的,即相同的输入输出相同的值。

第一次: 用户在网站上注册时,需要输入用户密码,通常是两个字段。现在密码被散列 h = H(passwd) 并存储在用户的数据库中。

稍后: 用户输入用户名和密码,然后服务器使用用户名从数据库中获取h。也散列当前输入的密码 pwd。如果 H(pwd) = h 那么输入的密码是正确的。您的服务器允许用户继续使用系统。

以上是密码系统的基础知识,但是,这还不够。密码散列的一些要点;

  1. 对于密码散列,我们至少不直接使用加密散列。密码散列需要很快,但是,密码散列需要很慢,甚至可以通过可调整的迭代来控制缓慢。这有助于系统适应所需的安全性。
  2. 我们用盐来对抗彩虹攻击;每个用户的随机盐将防止彩虹攻击。我们还使用 pepper 作为域分离的服务器盐。
  3. 我们需要内存硬密码哈希来防止大量 GPU/ASIC/FPGA 密码搜索。有关密码散列的一些比较,请参阅 hashcat。
  4. 也需要针对并行化的线程。
  5. 我们使用了专门设计的密码哈希算法,如 PBKDF2、Scrypt、Argon2。 Argon2 是最新密码哈希竞赛的获胜者。建议大家新系统使用Argon2id

最后一点也是最重要的一点是教育用户有关密码的知识。首先,然后介绍dicewire或类似的密码生成方法,其次,将它们介绍给密码管理器,如1passwords。

下面介绍了如何在不以明文形式存储密码的情况下对用户进行身份验证。

您将需要两个数据库列来执行此操作。第 1 列 - 密码哈希,第 2 列 - Salt

第 2 列 - Salt 是您的 code/system 为每个用户生成的随机生成值,它是随机的,不会暴露给任何 UI 或后端系统。 (我会在下面解释使用)

第 1 列 - 将是用户密码的哈希值 +(连接)盐。

您可以在此处阅读有关哈希的更多信息Common Hashing Algorithms

整个事情是如何运作的:

哈希: 哈希是一种基于算法为每个字符串创建唯一值的方法。唯一性因算法而异,但除非您有大量记录,否则应该没问题。此外,每个字符串的 HASH 值都是唯一的。这意味着字符串“test”的哈希将始终相同,假设为“123”

Salt: Salt 只是添加到每个密码的随机字符串。这样,哈希值计算为用户的密码 + SALT。这样可以确保即使多个用户使用相同的密码,他们的密码哈希 (HASH(Password+Salt)) 也将是唯一的。

设置密码

  • 当用户设置密码时,他们将提供一个密码。
  • 您的代码将随机生成一个“盐”值。
  • 将创建第三个变量 PasswordAndSalt = password + salt。
  • 然后会生成第四个变量hashValue = HASH(PasswordAndSalt)
  • 然后您可以将哈希值保存在密码哈希(第 1 列)中,将盐保存在盐中(第 2 列)。

加SALT是一种反制,如果两个用户使用同一个密码,HASH值还是会不一样。

正在验证用户 当用户输入用户名和密码时,您的代码将以这种方式执行。

检查用户名是否存在。

  • 如果用户名存在,获取其 SALT 值。
  • 获取用户提供的密码并连接您从数据库中获得的 SALT 值。
  • 计算密码+SALT的HASH值
  • 如果计算出的 HASH 值与数据库中的 SALT 值匹配,则对用户进行身份验证。
  • 否则,告诉用户认证失败。