这种密码验证的实现看起来安全吗?
Does this implementation of password authentication seem secure?
我正在创建一个 Web 应用程序,我需要为其安全地执行身份验证。通过阅读大量文章和帖子,我对实施得出了以下结论。
前端密码哈希:使用 bcrypt,我将使用唯一的盐对纯文本密码进行哈希处理。此盐存储在每个用户的数据库中。这个#1 salted-hash 然后被发送到 API.
后端密码哈希:使用 PBKDF2,#1 salted-hash 再次用另一种独特的盐进行哈希处理,生成#2 salted-hash,然后用#2 salt 存储在数据库中。
因此,数据库总共有#2 salted-hash、#1 salt 和#2 salt。
因此,在进行授权时,#1 salt 然后用于散列创建 #1 salted-hash 的纯文本密码。然后转到 API 进行授权,在那里我们从数据库中获取 #2 salt 以创建 #2 salted-hash,然后将其与数据库中的 #2 salted-hash 进行比较以进行授权。
抱歉,如果这个问题看起来多余,但我找不到任何特定于实现的答案。如果有人能帮助我,那就太好了!
您看过信息安全堆栈交换吗?例如。 this answer.
客户端密码散列通常被认为是无用且不必要的步骤,不会提高安全性。事实上,您的实施甚至可能产生不必要的副作用,实际上会降低安全性:user enumeration
根据您在授权过程中如何实施第一步,您可能容易受到用户枚举的攻击。如果在您的数据库中找不到匹配的用户,我假设您不会发回#1 盐:
- Anon 尝试使用与您数据库中的用户不匹配的 username/email 登录
- 由于该用户不存在,因此没有对应的#1 salt发回
- 您的 API 没有发回盐,甚至更糟的是,发送了 "user not found" 响应。不管怎样,匿名现在知道这个 username/email 没有帐户
反之亦然:
- Anon 尝试使用 username/email 登录
您数据库中的用户
- 由于该用户确实存在,API 发回该用户的#1 salt
- Anon 现在知道这个 username/email 有一个帐户
为了避免这种用户枚举,如果没有找到匹配的用户,你的 API 应该发回 #1 salt even,更重要的是,它应该总是发送相同盐响应相同username/email,否则可能发生:
- Anon 尝试使用与您数据库中的用户不匹配的 username/email 登录
- 由于该用户不存在,因此没有对应的#1 salt发回
- 您的 API 发回随机盐
- Anon 第二次尝试 相同 username/email
- 您的 API 发回 另一个 与第一个不相同的随机盐
- Anon 可以推断出您的 API 合成了两种盐以试图规避用户枚举
要解决这个问题,您必须想出一种方法来始终发回相同的盐以响应尝试多次的未知 username/email。但它不应该对每个未知用户都是相同的盐,否则匿名会做出相同的推论。
总而言之,这似乎是不必要的复杂性。这可能是客户端密码散列不被认为是一件好事的原因之一。
我正在创建一个 Web 应用程序,我需要为其安全地执行身份验证。通过阅读大量文章和帖子,我对实施得出了以下结论。
前端密码哈希:使用 bcrypt,我将使用唯一的盐对纯文本密码进行哈希处理。此盐存储在每个用户的数据库中。这个#1 salted-hash 然后被发送到 API.
后端密码哈希:使用 PBKDF2,#1 salted-hash 再次用另一种独特的盐进行哈希处理,生成#2 salted-hash,然后用#2 salt 存储在数据库中。
因此,数据库总共有#2 salted-hash、#1 salt 和#2 salt。
因此,在进行授权时,#1 salt 然后用于散列创建 #1 salted-hash 的纯文本密码。然后转到 API 进行授权,在那里我们从数据库中获取 #2 salt 以创建 #2 salted-hash,然后将其与数据库中的 #2 salted-hash 进行比较以进行授权。
抱歉,如果这个问题看起来多余,但我找不到任何特定于实现的答案。如果有人能帮助我,那就太好了!
您看过信息安全堆栈交换吗?例如。 this answer.
客户端密码散列通常被认为是无用且不必要的步骤,不会提高安全性。事实上,您的实施甚至可能产生不必要的副作用,实际上会降低安全性:user enumeration
根据您在授权过程中如何实施第一步,您可能容易受到用户枚举的攻击。如果在您的数据库中找不到匹配的用户,我假设您不会发回#1 盐:
- Anon 尝试使用与您数据库中的用户不匹配的 username/email 登录
- 由于该用户不存在,因此没有对应的#1 salt发回
- 您的 API 没有发回盐,甚至更糟的是,发送了 "user not found" 响应。不管怎样,匿名现在知道这个 username/email 没有帐户
反之亦然:
- Anon 尝试使用 username/email 登录 您数据库中的用户
- 由于该用户确实存在,API 发回该用户的#1 salt
- Anon 现在知道这个 username/email 有一个帐户
为了避免这种用户枚举,如果没有找到匹配的用户,你的 API 应该发回 #1 salt even,更重要的是,它应该总是发送相同盐响应相同username/email,否则可能发生:
- Anon 尝试使用与您数据库中的用户不匹配的 username/email 登录
- 由于该用户不存在,因此没有对应的#1 salt发回
- 您的 API 发回随机盐
- Anon 第二次尝试 相同 username/email
- 您的 API 发回 另一个 与第一个不相同的随机盐
- Anon 可以推断出您的 API 合成了两种盐以试图规避用户枚举
要解决这个问题,您必须想出一种方法来始终发回相同的盐以响应尝试多次的未知 username/email。但它不应该对每个未知用户都是相同的盐,否则匿名会做出相同的推论。
总而言之,这似乎是不必要的复杂性。这可能是客户端密码散列不被认为是一件好事的原因之一。