在哪里进行密码比较的最佳实践是什么?

7
当对网站上的用户进行身份验证时,哈希生成和比较应该在数据库还是网站中进行?
我的观点是,网站应将用户提供的密码(可能由Web服务器加密)传递给数据库。然后,数据库使用盐重新加密它并比较散列值。数据库然后向Web服务器响应用户凭据是否有效。这样,最少量的信息离开数据库,基本上只有一个是或否,没有存储的凭据信息。缺点是数据库需要做更多的工作。
另一个观点是应该在Web服务器中完成工作。在这种情况下,Web服务器会创建哈希并请求从数据库中检索存储的哈希值进行比较。在这种情况下,需要将盐从数据库传递回Web服务器以创建哈希。但是,随着Web服务器数量的增加,工作得到了共享。
个人认为第二种方法可能存在安全风险。如果Web服务器被攻击,可以从数据库中请求盐和哈希,并轻松破解它们。
执行上述操作的最佳实践是什么?我有遗漏/错过了什么吗?
谢谢

在应用层中进行哈希处理,并根据您的应用程序的实际情况,在数据库或应用程序中执行比较。 - Magnus Lind Oxlund
4个回答

2

2
你忽视了盐的目的。
盐用于防止针对哈希密码的字典攻击。如果你的密码是“peanut”,并哈希为12345,那么我可以预先生成一个包括你的密码在内的字典中每个单词的哈希列表,并通过查找我的预生成的一组密码哈希表快速找到你的密码。这就是最近LinkedIn发生的事情。如果密码使用了盐,则我必须在破解数据库后为每个盐值预先生成一个字典,这将极其昂贵。
此外,适当随机生成的盐可以防止攻击者知道你和我有相同的密码(不使用盐,我们将具有相同的哈希)。
我的观点是,盐不打算成为秘密。它们不是公开信息,但攻击者获得盐值+哈希并不一定意味着密码已经被破解。

2
我猜你会遇到的第一个问题(也是一个大问题)是你的数据库没有密码哈希函数。它可能有MD5()和SHA1(),但这些都是加密哈希函数。它是否有bcrypt()、scrypt()或PBKDF2()呢?
如果使用的是加密哈希函数而不是密码哈希函数,则像LinkedIn一样,密码很容易被破解。如果你没有使用以上函数之一,那么如果你的哈希内容泄露,你也会面临相似的风险。
接下来回答你的问题,假设你的数据库支持密码哈希算法(我选择bcrypt)。两个替代方案是:
在数据库中进行哈希:
$db->query("SELECT COUNT(*) FROM users WHERE username = '?' AND password = BCRYPT(?, (SELECT salt FROM user WHERE username = '?'))", $username, $password, $username);
if($row['count'] != 1)
{
  // Not authenticated.  Throw exception.
}

在这种情况下,原始密码被发送到数据库,返回一个简单的是或否(1或0)。这种数据库通信可以进行加密。哈希和盐从未在应用程序中保存。

应用程序中的哈希:

$db->query("SELECT username, salt, password FROM users WHERE username = '?', $username);
if(bcrypt($password, $row['salt']) != $row['password'])
{
  // Not authenticated.  Throw exception.
}

在这种情况下,哈希值和盐被从数据库中提取到应用程序中,并在那里对原始密码进行哈希和比较。与数据库的通信仍然可以加密。原始密码永远不会保存在数据库内存中。
为了效率,我们可以假设两个哈希算法都是用C(或某种编译语言)编写的,可能由操作系统提供,因此需要相同的时间。应用程序哈希选项通过网络接收更多数据,而数据库哈希选项发送更多数据并具有更复杂的查询(实际上是两个查询,一个获取盐,一个进行比较)。可能无法按照我编写的查询方式使用索引,但是查询可以进行重写。由于两种情况下数据的大小很可能仍然是一个TCP数据包,因此速度差异将是可忽略不计的。考虑到子查询,我认为应用程序哈希选项获胜。
对于暴露性。我认为原始密码比哈希和盐组合更敏感。因此,限制原始密码的暴露似乎是更安全的选择,使应用程序哈希成为最佳实践。

我猜我过于简化了这个例子,但你仍然可以将加密方法嵌入到数据库中,例如在SQL Server中使用CLR对象。 - Blootac
@Blootac 很好的观点。我已经添加了一个答案来回答实际问题,假设你的数据库有适当的哈希算法。 - Ladadadada
1
我来这里是为了寻找关于比较应该发生在哪里的答案。对此的答案仍然不清楚。您是否建议在客户端进行比较? - Mackie Messer
1
@MackieMesser 如果你所说的“客户端”是指浏览器,那么肯定不行。回顾我10年前的答案,现在我认为如果可能的话,使用数据库哈希和比较更好。您可以配置权限,以使应用程序具有的用户根本无法请求哈希和盐,这使得攻击者更难进行完整的哈希和盐转储。最终这可能并不重要。使用正确的哈希算法更加重要。 - Ladadadada

-1
计算机安全的一个好准则是,如果你不得不问,就不应该自己做。但是,如果你担心网站服务器被攻击导致密码泄露,那么一种方法是将身份验证移动到自己的系统上,并且根本不让网站服务器访问密码数据库。

4
我明白你的观点,但如果没有人提出问题,就没有人会学习,人们会继续犯错误。你应该更关注那些不问问题的人。感谢你的建议。 - Blootac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接