不使用数据库进行身份验证

信息安全 密码 验证 Web应用程序
2021-09-07 13:45:14

我受到Code Review上的一个问题的启发,该问题归结为:在没有数据库的情况下对用户进行身份验证的正确方法是什么?

如果您将凭证存储在一个数组、一个 XML 文件,甚至只是一个纯文本文件中,这会是完全相同的过程吗?

例如,让我们检查以下 PHP 代码:

$credentials = array(
    'UserA' => '$2y$10$PassForA',
    'UserB' => '$2y$10$PassForB'
);

$username = $_POST['username'];
$password = $_POST['password'];

if (isset($credentials[$username]) && password_verify($password, $credentials[$username])) {
    // Successfully authenticated
} else {
    // Permission denied
}

这是一种完全可以接受的存储凭据的方式吗?如果我们要从外部文件 (XML/txt) 中获取用户名和散列密码,是否需要区别对待?

4个回答

保存用户凭据的 XML 文件一个数据库。数据库的定义不仅限于 MySQL(或您想到的任何东西)。

如何对用户进行身份验证以及他们的凭据的确切存储位置是两个完全不同的问题。bcrypt 散列是一个 bcrypt 散列,无论它是存储在明文文件、MySQL 表还是 MongoDB 文档中。

当然,不同类型的数据库系统工作方式不同,需要不同的更新和加载数据的方式,但这与具体的用户身份验证无关。这些是数据存储的一般问题。

不使用数据库进行身份验证

我将把它解释为意义

是否有可能设计一个挑战-响应系统,让委托人证明他们是他们所说的人,而无需使用随委托人数量而扩展的存储量?即使用主体数量为 O(1) 的存储。


验证委托人的一种方法是让他们提供只有他们或您可以知道的东西。如果有人知道,而那个人不是你,那就是他们 :)

加密签名允许您生成字符串(令牌)

  1. 你可以把它给别人
  2. 你可以忘记它
  3. 他们可以把它还给你,你可以验证它真的是你给的

如果您信任身份验证主体不会泄露访问其帐户的秘密,您可以为他们提供签名输出,并使用签名检查来验证他们的身份。

如果你不能相信他们不会泄露秘密,那么你就不能相信他们不会泄露你已经散列到数据库中的密码,所以天真的用户泄露可以重放的秘密的可能性不是选择密码而不是签名的原因。


简单的签名检查不提供细粒度的撤销,但这是一个授权问题,而不是严格的身份验证问题。

以这种方式进行身份验证很好,但真正的诀窍是进行凭据管理和更新。用户如何更改密码?您是否正在重写您的源代码来做到这一点?

我当然见过存储在 XML、JSON 和 CSV 文件中的身份验证凭据。您需要采取一些步骤,例如在修改文件时获取锁、处理崩溃等,这些通常由数据库处理。

作为参考,默认情况下,unix 密码系统对不是“数据库”的平面文件(/etc/passwd 和 /etc/shadow)进行身份验证。拥有数据库不是关于安全性,而是关于性能。当您必须查看数百万行来查找用户 JohnDoe 时,性能会受到影响。另一方面,索引良好的数据库几乎可以立即找到同一个用户。

这也适用于将用户凭据直接存储到数组中 - 如果全部是硬编码,您将如何保存数据以及如何更新记录?

由于您在安全页面上询问,我假设您询问在平面文件系统上存储密码的最佳做法是什么。好吧,答案就像是数据库一样。你应该对你的密码进行加盐和哈希处理,这样如果文件被泄露,没有人可以对每个人的密码进行逆向工程。