为您的Web应用程序启用两因素身份验证
支持兩因素身份驗證(2FA)幾乎總是一個好主意,尤其是對于后臺系統(tǒng)。 2FA有許多不同的形式,其中一些包括SMS,TOTP甚至是硬件令牌 。
啟用它們需要類似的流程:
- 用戶轉(zhuǎn)到其個人資料頁面(如果要在注冊時強(qiáng)制使用2fa,請?zhí)^此頁面)
- 單擊“啟用兩因素身份驗證”
- 輸入一些數(shù)據(jù)以啟用特定的2FA方法(電話號碼,TOTP驗證碼等)
- 下次他們登錄時,除了用戶名和密碼外,登錄表單還會請求第二個因素(驗證碼)并將其與憑據(jù)一起發(fā)送
我將重點(diǎn)介紹Google Authenticator,它使用TOTP(基于時間的一次性密碼)生成一系列驗證碼。 想法是服務(wù)器和客戶端應(yīng)用程序共享一個密鑰。 基于該鍵和當(dāng)前時間,兩者都使用相同的代碼。 當(dāng)然,時鐘不能完全同步,因此服務(wù)器會接受一些窗口作為有效代碼。 請注意,如果您不信任Google的應(yīng)用程序,則可以使用以下相同的庫來實(shí)現(xiàn)自己的客戶端應(yīng)用程序(盡管您可以查看源代碼以確保沒有惡作劇發(fā)生)。
如何用Java(在服務(wù)器上)實(shí)現(xiàn)呢? 使用GoogleAuth庫 。 流程如下:
- 用戶轉(zhuǎn)到其個人資料頁面
- 單擊“啟用兩因素身份驗證”
- 服務(wù)器生成一個秘密密鑰,將其存儲為用戶配置文件的一部分,然后將URL返回到QR碼
- 用戶使用其Google Authenticator應(yīng)用程序掃描QR碼,從而在該應(yīng)用程序中創(chuàng)建新的個人資料
- 用戶在與QR碼一起顯示的字段中輸入應(yīng)用程序顯示的驗證碼,然后點(diǎn)擊“確認(rèn)”
- 服務(wù)器在用戶配置文件中將2FA標(biāo)記為已啟用
- (可選)您可以為用戶提供一些“便箋代碼”,以防他們丟失應(yīng)用程序或機(jī)密信息時可以寫下來。
- 如果用戶不掃描代碼或不驗證過程,則用戶個人資料將僅包含孤立的秘密密鑰,但不會被標(biāo)記為已啟用
- 應(yīng)該有一個選項,以后可以從其用戶個人資料頁面禁用2FA
從理論的角度來看,最重要的一點(diǎn)是共享密鑰。 密碼是對稱的,因此雙方(身份驗證器應(yīng)用程序和服務(wù)器)具有相同的密鑰。 它是通過用戶掃描的QR碼共享的。 如果此時攻擊者可以控制用戶的計算機(jī),則機(jī)密可能會泄露,從而2FA也會被攻擊者濫用。 但這不在威脅模型中,換句話說,如果攻擊者可以訪問用戶的計算機(jī),則無論如何都已經(jīng)造成了損害。
注意:您可能會看到此過程稱為2步身份驗證或2因子。 “因素”是:“您知道的東西”,“您擁有的東西”和“您自己的東西”。 您可以將TOTP視為“您知道”的另一件事,但是您也可以將帶有安全存儲的密鑰的電話視為“您擁有的”東西。 在這種特殊情況下,我不堅持使用任何一種術(shù)語。
登錄后,流程如下:
- 用戶輸入用戶名和密碼,然后單擊“登錄”
- 使用AJAX請求,頁面詢問服務(wù)器此電子郵件是否已啟用2FA
- 如果未啟用2FA,只需提交用戶名和密碼表格
- 如果啟用了2FA,則不會提交登錄表單,而是顯示一個附加字段,以允許用戶從身份驗證器應(yīng)用程序中輸入驗證碼
- 用戶輸入代碼并按登錄后,即可提交表單。 使用相同的登錄按鈕,或使用新的“驗證”按鈕,或使用驗證輸入+按鈕可能是全新的屏幕(隱藏用戶名/密碼輸入)。
- 然后,服務(wù)器再次檢查用戶是否啟用了2FA,如果是,則驗證驗證碼。 如果匹配,則登錄成功。 如果不是,則登錄失敗,并且允許用戶重新輸入憑據(jù)和驗證碼。 請注意,根據(jù)用戶名/密碼錯誤或代碼錯誤,您可能會有不同的響應(yīng)。 您甚至可以在嘗試顯示驗證碼輸入之前嘗試登錄。 這種方法可以說是更好的方法,因為這樣您就不會向潛在的攻擊者透露用戶使用2FA。
我說的是用戶名和密碼,這可以應(yīng)用于任何其他身份驗證方法。 從OAuth / OpenID Connect / SAML提供程序獲得成功確認(rèn)之后,或者從SecureLogin獲得令牌之后,您可以請求第二個因素(代碼)。
在代碼中,上述過程如下所示(使用Spring MVC;為簡便起見,我將控制器和服務(wù)層合并。您可以使用將當(dāng)前登錄的用戶詳細(xì)信息提供給控制器的方式替換@AuthenticatedPrincipal位)。 假設(shè)方法在控制器中映射到“ / user /”:
@RequestMapping(value = "/init2fa", method = RequestMethod.POST) @ResponseBody public String initTwoFactorAuth(@AuthenticationPrincipal LoginAuthenticationToken token) {User user = getLoggedInUser(token);GoogleAuthenticatorKey googleAuthenticatorKey = googleAuthenticator.createCredentials();user.setTwoFactorAuthKey(googleAuthenticatorKey.getKey());dao.update(user);return GoogleAuthenticatorQRGenerator.getOtpAuthURL(GOOGLE_AUTH_ISSUER, email, googleAuthenticatorKey); }@RequestMapping(value = "/confirm2fa", method = RequestMethod.POST) @ResponseBody public boolean confirmTwoFactorAuth(@AuthenticationPrincipal LoginAuthenticationToken token, @RequestParam("code") int code) {User user = getLoggedInUser(token);boolean result = googleAuthenticator.authorize(user.getTwoFactorAuthKey(), code);user.setTwoFactorAuthEnabled(result);dao.update(user);return result; }@RequestMapping(value = "/disable2fa", method = RequestMethod.GET) @ResponseBody public void disableTwoFactorAuth(@AuthenticationPrincipal LoginAuthenticationToken token) {User user = getLoggedInUser(token);user.setTwoFactorAuthKey(null);user.setTwoFactorAuthEnabled(false);dao.update(user); }@RequestMapping(value = "/requires2fa", method = RequestMethod.POST) @ResponseBody public boolean login(@RequestParam("email") String email) {// TODO consider verifying the password here in order not to reveal that a given user uses 2FAreturn userService.getUserDetailsByEmail(email).isTwoFactorAuthEnabled(); }QR碼生成使用Google的服務(wù),從技術(shù)上講,它也為Google提供了秘密密鑰。 我懷疑它們除了生成QR碼外還會存儲它,但是,如果您不信任它們,則可以實(shí)現(xiàn)自己的QR碼生成器, 那么自己生成QR碼應(yīng)該不難 。
在客戶端,它是對上述方法的簡單AJAX請求(旁注:我覺得AJAX一詞不再流行,但我不知道如何稱呼它們。異步,背景或Javascript)。
$("#two-fa-init").click(function() {$.post("/user/init2fa", function(qrImage) {$("#two-fa-verification").show();$("#two-fa-qr").prepend($('<img>',{id:'qr',src:qrImage}));$("#two-fa-init").hide();}); });$("#two-fa-confirm").click(function() {var verificationCode = $("#verificationCode").val().replace(/ /g,'')$.post("/user/confirm2fa?code=" + verificationCode, function() {$("#two-fa-verification").hide();$("#two-fa-qr").hide();$.notify("Successfully enabled two-factor authentication", "success");$("#two-fa-message").html("Successfully enabled");}); });$("#two-fa-disable").click(function() {$.post("/user/disable2fa", function(qrImage) {window.location.reload();}); });登錄表單代碼在很大程度上取決于您正在使用的現(xiàn)有登錄表單,但是重點(diǎn)是使用電子郵件(和密碼)調(diào)用/ requires2fa以檢查是否啟用了2FA,然后顯示驗證碼輸入。
總體而言,兩因素身份驗證的實(shí)現(xiàn)很簡單,我建議將其用于大多數(shù)系統(tǒng),在這些系統(tǒng)中,安全性比用戶體驗的簡單性更為重要。
翻譯自: https://www.javacodegeeks.com/2017/10/enabling-two-factor-authentication-web-application.html
總結(jié)
以上是生活随笔為你收集整理的为您的Web应用程序启用两因素身份验证的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ue注释快捷键(ue批量注释)
- 下一篇: 电脑绝地求生赛季通行证(绝地求生最新赛季