2

在 Google Authenticator 应用程序中,您可以扫描 QR 码或手动键入颁发者提供的密钥。

在下面的屏幕截图中,您可以看到 Google Security 设置中的 2FA 设置,显示如何按照第二种方法获取 TOTP。

Google 2FA 设置 - Google 身份验证器设置

我的问题是:这个密钥是如何生成的?

我正在尝试使用 Google Authenticator 为我的网站支持 2FA,我发现了许多关于如何生成 QR 码的参考资料和文档,但甚至没有提到替代方法。

编辑:

为了更清楚一点,我在 Grails 3 webapp 中使用 Google Authenticator 支持 2FA。我已经实现了整个用户流程,为每个用户生成一个密钥(Base32字符串),提供一个二维码供用户扫描,并在登录时验证 TOTP。我用作依赖项:

  • org.jboss.aerogear:aerogear-otp-java, aerogear OTP以方便地根据 GA 的 TOTP 验证用户密钥
  • org.grails.plugins:qrcode, qrcode Grails插件生成二维码

我的问题是关于在 Google Authenticator 应用程序中添加新条目的两种方法:1. 扫描 QR 码(我这边一切正常) 2. 手动输入帐户名称和字母代码(在我的第一个屏幕截图中,代码是在 Google 安全设置中提供)

您可以看到来自 GA for Android 的解释性屏幕截图:

Google 2FA 设置 - Google 身份验证器设置

如何生成并向用户提供此类代码(从fzee第一个屏幕截图开始,并在第二个屏幕截图中命名为“提供的密钥”)?我确定它是同样数据字符串的编码,也编码在 QR 码中,但我不知道是哪个(不简单Base32)。

4

4 回答 4

3

密钥 = 秘密

密钥应与您生成的密钥相同。只需通过打开 google 身份验证器并手动将其添加为密钥来对其进行测试。

查看以下链接中的文档: https: //support.google.com/accounts/answer/1066447?co= GENIE.Platform%3DiOS&hl=en

于 2018-01-26T01:46:11.870 回答
1

Google Authenticator Setup QR 码是基于一些东西生成的,其中之一是“密钥”,因此根据您用于将其构建到您的站点中的代码库,通常首先生成“密钥”并且该密钥然后用于生成二维码。

如果您查看此 node.js 模块,您可以看到我在说什么

// generate base32 secret
var secret = GA.encode('base 32 encoded user secret') || GA.secret();

// get QRCode in SVG format
var qrCode = GA.qrCode('akanass', 'otp.js', secret);

https://github.com/njl07/otp.js/#qrcode-generation

这是另一个示例站点,您可以在其中手动生成 QR 码,您可以提供Label, User, Key and URL, 然后将生成 QR 码。

https://dan.hersam.com/tools/gen-qr-code.html

让我知道您尝试使用什么代码库将其实现到您的网站中,然后我可以帮助您追踪密钥的生成位置

于 2017-11-14T01:43:48.707 回答
1
And View

@model _2FAGoogleAuthenticator.ViewModel.LoginModel

@{
    ViewBag.Title = "Login";
}

<h2>Login</h2>

@* Here we will add 2 form, 1 for Login and another one for 2FA token verification form *@
@if (ViewBag.Status == null || !ViewBag.Status)
{
    <!--Show login form here, Viewbag.Status is used for check is already veirfied from our database or not-->
    <div>@ViewBag.Message</div>
    <div>
        @using (Html.BeginForm())
        {
            <div class="form-group">
                <label for="Username">Username : </label>
                @Html.TextBoxFor(a => a.Username, new { @class = "form-control"})
            </div>
            <div class="form-group">
                <label for="Password">Password : </label>
                @Html.TextBoxFor(a => a.Password, new { @class="form-control", type="password"})
            </div>
            <input type="submit" value="Login" class="btn btn-default" />
        }
    </div>
}
else
{
    <!--Show 2FA verification form here-->
    <div>@ViewBag.Message</div>
    <div>
        <img src="@ViewBag.BarcodeImageUrl"/>
    </div>
    <div>
        **Manual Setup Code : @ViewBag.SetupCode**
    </div>
    <div>
        @using (Html.BeginForm("Verify2FA","Home", FormMethod.Post))
        {
            <input type="text" name="passcode" />
            <input type="submit" class="btn btn-success" /> 
        }
    </div>
}
于 2017-11-21T16:23:37.307 回答
0
public class HomeController : Controller
    {
        private const string key = "key"; // any 10-12 char string for use as private key in google authenticator
        public ActionResult Login()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Login(LoginModel login)
        {
            string message = "";
            bool status = false;

            //check username and password form our database here
            //for demo I am going to use Admin as Username and Password1 as Password static value
            if (login.Username == "sanket" && login.Password == "123")
            {
                status = true; // show 2FA form
                message = "2FA Verification";
                Session["Username"] = login.Username;

                //2FA Setup
                TwoFactorAuthenticator tfa = new TwoFactorAuthenticator();
                string UserUniqueKey = login.Username + key; //as Its a demo, I have done this way. But you should use any encrypted value here which will be unique value per user 
                Session["UserUniqueKey"] = UserUniqueKey;
                var setupInfo = tfa.GenerateSetupCode("Sanket Security", login.Username, UserUniqueKey, 300, 300);
                ViewBag.BarcodeImageUrl = setupInfo.QrCodeSetupImageUrl;
                ViewBag.SetupCode = setupInfo.ManualEntryKey;
            }
            else
            {
                message = "Invalid credential";
            }
            ViewBag.Message = message;
            ViewBag.Status = status;
            return View();
        }

        public ActionResult MyProfile()
        {
            if (Session["Username"] == null || Session["IsValid2FA"] == null || !(bool)Session["IsValid2FA"])
            {
                return RedirectToAction("Login");
            }
            ViewBag.Message = "Welcome " + Session["Username"].ToString();
            return View();
        }
        public ActionResult Verify2FA()
        {
            var token = Request["passcode"];
            TwoFactorAuthenticator tfa = new TwoFactorAuthenticator();
            string UserUniqueKey = Session["UserUniqueKey"].ToString();
            bool isValid = tfa.ValidateTwoFactorPIN(UserUniqueKey, token);
            if (isValid)
            {
                Session["IsValid2FA"] = true;
                return RedirectToAction("MyProfile", "Home");
                token=string.Empty;
            }
            return RedirectToAction("Login", "Home");
        }
    }
}
于 2017-11-21T16:19:06.630 回答