我怀疑你会遇到的第一个问题(这是一个大问题)是你的数据库没有密码哈希函数。当然,它可能有 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 数据包,因此速度差异可以忽略不计。由于子查询,我认为这是应用程序哈希选项的胜利。
为了曝光。我认为原始密码比哈希和盐更敏感。因此,限制原始密码的暴露似乎是更安全的选择,使应用程序散列成为最佳实践。