“Google Two Factor Authenticator” accountSecretKey 是否应该存储到我的数据库中?

问题描述

我试图了解 Google 双重身份验证器 流程的工作原理,以便将其整合到我的网站中。我的理解是这个过程有两个不同的部分

  1. 我网站上的一位用户启用了 2FA,这在我的用户和应用之间创建了链接。这是一次性步骤,不会在每次登录尝试时发生。
  2. 每次用户登录时,他都需要提供来自 Google 身份验证器应用的六位数代码

现在,以下代码生成二维码图像和设置代码以启用 2FA 并将帐户链接到 Google 身份验证。

TwoFactorAuthenticator tfa = new TwoFactorAuthenticator();
string accountSecretKey = Guid.NewGuid();
var setupInfo = tfa.GenerateSetupCode("Dotnet Awesome",login.Username,accountSecretKey,300,300);
ViewBag.BarcodeImageUrl = setupInfo.QrCodeSetupImageUrl;
ViewBag.SetupCode = setupInfo.ManualEntryKey;

现在在每次请求时,我都会使用以下代码用户进行身份验证

TwoFactorAuthenticator tfa = new TwoFactorAuthenticator();
tfa.ValidateTwoFactorPIN(accountSecretKey,"Six Digit Code");

问题

在上面的代码中,accountSecretKey 代码是否必须保存到我的数据库中,以便每次我想验证时都可以传递它?或者,我每次登录尝试都必须重新创建 accountSecretKey 什么?如果这个代码是我要存储到我的数据库中的东西,它是否也应该像密码一样加密?

解决方法

当我设置它时,我倾向于:

在数据库中有一个 G2FAEnabled 列,一个用于用户的 SecretKey

生成一个唯一的密钥并用它来为用户使用的页面生成条形码 设置 G2FA,在服务器端记住它(把它放在数据库中)但不要设置启用列>

要求用户在将您的网站添加到身份验证器后扫描或键入他们的设备显示的代码。这证明他们的设备设置正确,他们的设备时钟正确等

如果他们输入的数字是正确的,将启用的列设置为 true 并锁定内容,以便密钥现在不可更改(更改它会杀死他们的 2FA)

从那时起,用户必须为当前服务器时间和存储在服务器上的密钥提供正确的基于时间的 pin。他们的设备时钟必须与服务器保持同步。您可以通过检查例如当前时间的任一侧 6 次尝试找到匹配来实现时钟漂移的容限(这意味着设备时钟可以相对于服务器时间加减 3 分钟并且仍然匹配)。

任何尝试停用 2FA(将启用的列设置为 false)也应该需要有效的 2FA 代码,但是您的客户服务部门的替代流程(例如查看用户的护照)应该允许在不知情的情况下进行重置

您不必加密数据库中的密钥 - 您必须对其进行解密才能使用它,而且它不像存储明文密码这样的失礼(如果您的数据库被盗,这是一个问题,因为用户一直重复使用密码,因此您的数据库被盗可能意味着您会泄露所有其他服务的用户密码),因为它应该是随机数据,在您的组织之外没有任何意义,因此它不会帮助黑客破解进入使用相同 2FA 设备的另一个用户站点。

通常,如果有人能够窃取您的数据库,他们已经达到了可以窃取必要的位来解密您加密存储的任何内容的地步,但是如果您确定您的数据库可能会被盗,但您的网络服务器将保持安全,然后通过一切手段加密数据库数据