身份验证:用户名(电子邮件)和密码在一个数据库字段中一起散列

信息安全 验证 密码学 数据库 验证
2021-09-02 16:12:40

我目前正在为我们的客户开发一个带有 PHP 框架的平台。

客户的 IT 部门负责人希望我们使用包含电子邮件+密码+salt(散列)的一个数据库字段来处理身份验证,因此该表中没有纯文本电子邮件字段,并且密码更安全(他的推理)。用户应该能够使用他的电子邮件地址和密码登录。因此,电子邮件地址用作用户名。这背后的想法是,用户的电子邮件地址对我们客户的业务非常重要,IT 负责人希望隐藏登录表中的电子邮件地址,以防可能受到攻击。(例如,黑客可以访问登录表)

这当然是唯一可能的,因为用于登录的散列电子邮件地址链接到他在个人资料表中的电子邮件地址。基本上,此过程需要两个表才能工作。这些表当然在同一个数据库中。一个带有哈希组合字段(电子邮件、密码、盐)的登录表和一个配置文件表,其中包含一个字段中的明文电子邮件。我们称之为 profile_email。

我强烈建议不要使用此解决方案,因为我以前从未听说过此解决方案,并且我已经确定了此解决方案的一些可能问题。

所以我的问题是:这是一个安全可行的解决方案吗?你能想到任何不可预见的问题吗?你听说过类似的解决方案吗?

2个回答

据我所知,这个方案没有任何意义。正如您所指出的,您仍然需要为用户存储明文电子邮件地址,因此使用明文电子邮件和电子邮件 + 密码 + 盐哈希与仅使用明文电子邮件和密码 + 盐哈希相比,没有任何显着的安全优势.

正如我确定您已经注意到的那样,没有纯文本电子邮件(无论它是在配置文件表还是登录表中)仅依赖于电子邮件 + 密码 + 盐的单个哈希值是不可行的(你必须去通过每一行,获取盐,计算散列,查看它是否匹配,如果不匹配,从下一行获取盐,计算散列,查看它是否匹配,等等,等等……)并且将是一场安全灾难,因为它允许攻击者通过一次登录尝试测试站点上所有用户的哈希值,而不是只能测试特定用户的哈希值。

我看不出有什么好的理由这样做。它并没有提高安全性,它确实增加了复杂性,而且实施充满了危险。您应该礼貌但坚定地要求客户遵循标准的最佳实践,而不是试图发明他自己的轻率方案。

您和 IT 部门负责人之间会不会有一些误解?正如 Xander 已经指出的那样,这样的计划是行不通的,我什至会补充说这很荒谬。为了对用户进行身份验证,必须对登录电子邮件地址执行数据库查找以检索用于比较的相应哈希:

SELECT hash from Users WHERE email=?;
if($hash == hash_func($password)) then Grant access

您现在提出的是通过添加 JOIN 操作来使查找更加复杂,以避免直接查找 Users 表:

SELECT U.hash from Users U INNER JOIN Profile P WHERE P.id = U.id AND P.email=?;

查询位于同一数据库上的两个表根本不会提高安全性。它还将使身份验证过程更加繁琐且计算成本更高。

如果需要保护电子邮件地址,则不能将其用作身份验证方案的一部分。解决此问题的典型方法是将用户名与密码结合使用。这将消除基于电子邮件地址进行查找的需要:

SELECT hash from Users WHERE username=?;

然后它还允许您加密电子邮件地址以保护它们。如果您的数据库托管在与您的应用程序不同的服务器上,则任何设法访问该数据库的人都可能无法检索电子邮件地址。


感谢您的澄清。上述答案是对您在问题第三段中所述的建议的回应。正如我从您下面的评论中了解到的那样,您的客户提出了一种完全不同的方法,它不需要使用第二个(配置文件)表:

SELECT id from Users WHERE hash=?;

仅当您确保表中的所有哈希都是UNIQUE时,上述方案才有效。由于没有查找登录电子邮件,因此您需要解决以下安全问题:

  • 如何防止对个人帐户进行暴力破解
  • 随着数据库变大,匹配哈希的可能性
  • 您的站点处理登录页面上的 DDOS 攻击的能力,因为始终执行散列

顺便问一下,您的客户是否接受用户输入错误密码并以其他用户身份登录的风险?如果是,那么您可以继续此操作。