为您的Web应用程序启用两因素身份验证

支持两因素身份验证(2FA)几乎总是一个好主意,尤其是对于后台系统。 2FA有许多不同的形式,其中一些包括SMS,TOTP甚至是硬件令牌 。

启用它们需要类似的流程:

  • 用户转到其个人资料页面(如果要在注册时强制使用2fa,请跳过此页面)
  • 单击“启用两因素身份验证”
  • 输入一些数据以启用特定的2FA方法(电话号码,TOTP验证码等)
  • 下次他们登录时,除了用户名和密码外,登录表单还会请求第二个因素(验证码)并将其与凭据一起发送

我将重点介绍Google Authenticator,它使用TOTP(基于时间的一次性密码)生成一系列验证码。 想法是服务器和客户端应用程序共享一个密钥。 基于该键和当前时间,两者都使用相同的代码。 当然,时钟不能完全同步,因此服务器会接受一些窗口作为有效代码。 请注意,如果您不信任Google的应用程序,则可以使用以下相同的库来实现自己的客户端应用程序(尽管您可以查看源代码以确保没有恶作剧发生)。

如何用Java(在服务器上)实现呢? 使用GoogleAuth库 。 流程如下:

  • 用户转到其个人资料页面
  • 单击“启用两因素身份验证”
  • 服务器生成一个秘密密钥,将其存储为用户配置文件的一部分,然后将URL返回到QR码
  • 用户使用其Google Authenticator应用程序扫描QR码,从而在该应用程序中创建新的个人资料
  • 用户在与QR码一起显示的字段中输入应用程序显示的验证码,然后点击“确认”
  • 服务器在用户配置文件中将2FA标记为已启用
  • (可选)您可以为用户提供一些“便笺代码”,以防他们丢失应用程序或机密信息时可以写下来。
  • 如果用户不扫描代码或不验证过程,则用户个人资料将仅包含孤立的秘密密钥,但不会被标记为已启用
  • 应该有一个选项,以后可以从其用户个人资料页面禁用2FA

从理论的角度来看,最重要的一点是共享密钥。 密码是对称的,因此双方(身份验证器应用程序和服务器)具有相同的密钥。 它是通过用户扫描的QR码共享的。 如果此时攻击者可以控制用户的计算机,则机密可能会泄露,从而2FA也会被攻击者滥用。 但这不在威胁模型中,换句话说,如果攻击者可以访问用户的计算机,则无论如何都已经造成了损害。

注意:您可能会看到此过程称为2步身份验证或2因子。 “因素”是:“您知道的东西”,“您拥有的东西”和“您自己的东西”。 您可以将TOTP视为“您知道”的另一件事,但是您也可以将带有安全存储的密钥的电话视为“您拥有的”东西。 在这种特殊情况下,我不坚持使用任何一种术语。

登录后,流程如下:

  • 用户输入用户名和密码,然后单击“登录”
  • 使用AJAX请求,页面询问服务器此电子邮件是否已启用2FA
  • 如果未启用2FA,只需提交用户名和密码表格
  • 如果启用了2FA,则不会提交登录表单,而是显示一个附加字段,以允许用户从身份验证器应用程序中输入验证码
  • 用户输入代码并按登录后,即可提交表单。 使用相同的登录按钮,或使用新的“验证”按钮,或使用验证输入+按钮可能是全新的屏幕(隐藏用户名/密码输入)。
  • 然后,服务器再次检查用户是否启用了2FA,如果是,则验证验证码。 如果匹配,则登录成功。 如果不是,则登录失败,并且允许用户重新输入凭据和验证码。 请注意,根据用户名/密码错误或代码错误,您可能会有不同的响应。 您甚至可以在尝试显示验证码输入之前尝试登录。 这种方法可以说是更好的方法,因为这样您就不会向潜在的攻击者透露用户使用2FA。

我说的是用户名和密码,这可以应用于任何其他身份验证方法。 从OAuth / OpenID Connect / SAML提供程序获得成功确认之后,或者从SecureLogin获得令牌之后,您可以请求第二个因素(代码)。

在代码中,上述过程如下所示(使用Spring MVC;为简便起见,我将控制器和服务层合并。您可以使用将当前登录的用户详细信息提供给控制器的方式替换@AuthenticatedPrincipal位)。 假设方法在控制器中映射到“ / 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的服务,从技术上讲,它也为Google提供了秘密密钥。 我怀疑它们除了生成QR码外还会存储它,但是,如果您不信任它们,则可以实现自己的QR码生成器, 那么自己生成QR码应该不难 。

在客户端,它是对上述方法的简单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();});
});

登录表单代码在很大程度上取决于您正在使用的现有登录表单,但是重点是使用电子邮件(和密码)调用/ requires2fa以检查是否启用了2FA,然后显示验证码输入。

总体而言,两因素身份验证的实现很简单,我建议将其用于大多数系统,在这些系统中,安全性比用户体验的简单性更为重要。

翻译自: https://www.javacodegeeks.com/2017/10/enabling-two-factor-authentication-web-application.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348436.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

redis java序列化_java处理redis的几种序列化策略

简单记录一下java处理redis的几种序列化策略&#xff0c;这里使用的环境是springboot 2.0.4springboot中提供了StringRedisTemplate和RedisTemplate两种序列化类&#xff0c;它们都只能读自己存的数据&#xff0c;即数据互不相通。主要区别如下&#xff1a;1、采用的序列化策略…

java 访问内部类的属性_java中的内部类详细总结

内部类不是很好理解&#xff0c;但说白了其实也就是一个类中还包含着另外一个类如同一个人是由大脑、肢体、器官等身体结果组成&#xff0c;而内部类相当于其中的某个器官之一&#xff0c;例如心脏&#xff1a;它也有自己的属性和行为(血液、跳动)显然&#xff0c;此处不能单方…

迟来总比没有好:SSE或服务器发送的事件现在已在JAX-RS中

服务器发送的事件 &#xff08;或简称为SSE &#xff09;是非常有用的协议&#xff0c;它允许服务器通过HTTP将数据推送到客户端。 这是我们的网络浏览器支持的年龄&#xff0c;但令人惊讶的是&#xff0c; JAX-RS规范在很长一段时间内都忽略了这一点。 尽管Jersey提供了适用于…

java 面向对象继承的思想_Java面向对象思想

Java类的定义&#xff1a;成员变量会默认初始化&#xff0c;局部变量不会默认初始化。如何在内存中区分类和对象&#xff1a;♦类是静态的概念&#xff0c;代码区♦对象是new出来的&#xff0c;位于堆内存&#xff0c;类的每一个成员变量在不同的对象中都有不同的值(除了静态变…

java 垃圾回收手动回收_Java垃圾回收(4)

java 垃圾回收手动回收G1&#xff1a;垃圾优先 G1收集器是热点JVM中要实现的最新收集器。 自Java 7 Update 4以来&#xff0c;它一直是受支持的收集器。OracleGC团队也公开表示&#xff0c;他们对低暂停GC的希望是完全实现的G1。 这篇文章来自我之前的垃圾收集博客文章&#xf…

使用正确的垃圾收集器将Java内存使用量降至最低

大小对于软件至关重要。 很明显&#xff0c;与大型整体方法相比&#xff0c;在微服务体系结构中使用小型组件具有更多优势。 最新的Java版本的Jigsaw可帮助分解旧应用程序或从头开始构建新的云原生应用程序。 这种方法减少了磁盘空间&#xff0c;构建时间和启动时间。 但是&am…

java 鼠标画多个圆形_点击鼠标不同的建(左、中、右)画一个不同颜色的圆

[java]代码库import java.awt.Color;import java.awt.Graphics;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import javax.swing.JFrame;public class T1 extends JFrame{int x;int y;Color c;public T1(){this.setSize(600,400);this.setDefaultCl…

jslint4java_JSLint检测javascript的错误提示

“Missing semicolon.” : “缺少分号.”,“Use the function form of \”use strict\”.” : “使用标准化定义function.”,“Unexpected space after ‘-’.” : “在’-后面不应出现空格.”,“Expected a JSON value.” : “请传入一个json的值.”,“Mixed spaces and tabs.…

jar运行 osgi保存_自动化的OSGi测试运行程序

jar运行 osgi保存在我的团队成员中&#xff0c;我以忘记维护&#xff08;JUnit&#xff09;测试套件而闻名。 我只是无法完成手动添加测试套件这一额外步骤。 幸运的是&#xff0c;有连续的集成服务器可以按命名模式收集测试。 如果我介绍的一项孤立测试失败了&#xff0c;那么…

mysql 去掉默认约束_06. 默认约束-创建、添加和删除

# 数据库的基本操作创建 删除 数据库、创建 删除表修改 表名 数据类型 字段名 添加字段删除 字段 调整字段位置 更换存储引擎 删除外键删除 数据表 包括被关联父表# 数据完整性六项约束主键约束(PRIMARY KEY)自增约束(AUTO_INCREMENT PRIMARY KEY)唯一约束(UNIQUE)默认约束(DEF…

通过粘性仙人掌基元进行延迟加载和缓存

您显然知道什么是延迟加载 &#xff0c;对吗&#xff1f; 而且您无疑知道缓存 。 据我所知&#xff0c;Java中没有一种优雅的方法来实现它们中的任何一个。 这是我在Cactoos原语的帮助下为自己找到的。 Matteo Garrone的《 Reality&#xff08;2012&#xff09;》 假设我们需…

mysql与sim900a_sim900a的应用,基于SIM900A-GPRS模块的远程文件传输实例

SIM900A是一个比较实用的GPRS模块&#xff0c;进行简单的配置就可以进行用于数据传输&#xff0c;配置使用AT指令进行交互&#xff0c;用GPRS远程传输数据时&#xff0c;有两种方式&#xff0c;一种是正常的模式&#xff0c;没法送一次要发送0x1a来开启数据发送&#xff0c;另一…

java语言编程基础_java语言编程基础

java语言基本要素高级语言如c、c#、java等都有一些共同性的东西&#xff1a;关键字、标识符、运算符、注释、数据类型、常量和变量、语句、函数、数组。高级语言在这些要素上大同小异。Java关键字&#xff1a;一些有特定含义&#xff0c;有专门用途的字符串(keyword)。Java中关…

junit mockito_JUnit和Mockito合作

junit mockito这次&#xff0c;我想对测试框架Mockito进行概述。 毫无疑问&#xff0c;这是用于测试Java代码的最受欢迎的工具之一。 我已经对Mockito的竞争对手EasyMock进行了概述。 这篇文章将基于有关EasyMock的示例应用程序。 我的意思是代表咖啡机功能的类。 使用Mockito…

debian10树莓派4安装mysql_树莓派4上如何安装 Raspbian Buster

随着 Raspberry Pi 4 主板的问世&#xff0c;了解如何使用Raspbian Buster设置您的操作系统。你的新Pi 4到了邮箱&#xff0c;你已经设置了办公桌&#xff0c;您已准备好安装操作系统。对于初学者来说&#xff0c;Raspbian为Pi制造商提供了出色的桌面体验。最重要的是&#xff…

借助财务客户评估解决方案在云中构建AppDev

现代JBoss BRMS时代最古老的业务逻辑演示是2012年6月发布的“ 客户评估”示例 。 那时&#xff0c;JBoss BRMS包含规则&#xff0c;事件和流程。 该项目提供了一个完整安装和配置的环境&#xff0c;用于展示该项目和所有可用的BPM组件。 它包括一个带有单元测试的JBoss Develo…

jvm 性能_JVM性能魔术

jvm 性能HotSpot是我们众所周知和喜爱的JVM&#xff0c;是Java和Scala汁流淌的大脑。 多年来&#xff0c;许多工程师对其进行了改进和调整&#xff0c;并且每次迭代时&#xff0c;其代码执行的速度和效率都接近于本机编译代码。 JIT&#xff08;“及时”&#xff09;编译器是…

java高级编程期末考试题_java高级编程考题

Java高级课程测试1在进行swing开发时&#xff0c;经常用的布局管理器有那几种&#xff1f;(5)2Gui组件&#xff0c;容器&#xff0c;框架&#xff0c;到底有怎样的关系&#xff0c;请举例说明&#xff1f;(5)3在进行swing开发中会用到事件处理&#xff0c;那事件处理的三个主要…

spring 事务 会话_测试Spring的“会话”范围

spring 事务 会话在基于Spring的Web应用程序中&#xff0c;bean的作用域可以是用户“会话”。 从本质上讲&#xff0c;这意味着对会话范围Bean的状态更改仅在用户会话范围内可见。 本条目的目的是简单地突出显示Spring Test MVC提供的一种方法&#xff0c;用于测试将会话范围的…

Hollowjars,部署扫描程序以及Wildfly群体为何很棒

在上一篇文章中&#xff0c;我描述了如何使用OpenLiberty和maven作为独立服务器或maven构建的一部分来启动服务器&#xff0c;以及如何创建fatjar包。 在这篇文章中&#xff0c;我正在研究如何使用Wildfly群。 我仍在尝试使MicroProfile在Wildfly full上运行&#xff0c;因此&…