2FA的原理与应用

什么是 2FA

2FA(Two-Factor Authentication,双因素认证)就是一种账号保护措施,在用户登录时额外添加一层认证步骤,以加强账号的安全性。双因素认证中的第一个因素是“你知道的”,比如账号密码,而第二个因素是“你拥有的”,比如手机短信验证码。

如果账号是单因素认证的,也就是只通过账号密码就可以登录账号的话,那么一旦账号密码被泄露了,则账号也就被其他人登录了。而如果账号是双因素认证的,那么即使账号密码泄露了,由于登录账号还需要验证诸如短信验证码等信息,而这些信息是只有我们自己才拥有的(SIM 卡插在我们自己的手机里),所以其他人还是无法登录我们的账号。因此双因素认证可以极大地加强账号的安全性。

OTP 生成器

很多应用的系统里没有增加手机号的支持,这些应用为了启动双因素认证,都会为你生成一个密钥,然后你将这个密钥放到自己的手机里,之后在自己的手机里通过 OTP(One-Time Password,一次性密码)生成器可以生成一次性密码,使用这个密码就可以登录账号了,以代替短信验证码登录。

OTP 生成器会基于特定的算法为一个密钥在不同的时间段生成特定的密码,也就是“密钥 + 时间 → 密码”,所以生成的密码都是可预测的。

网上有很多 OTP 生成器,推荐使用 https://2fa.live/,在里面输入密码就可以生成在当前时间段的一次性密码。

Google Authenticator

自己管理密钥和生成一次性密码是比较麻烦的一件事情,这是就可以使用一些认证器来帮我们管理和生成一次性密码,比较常见的就是 Google Authenticator。

许多应用为了我们能方便将密钥一键导入像 Google Authenticator 这样的认证器中,通常会将密钥信息放在一个二维码中,然后我们使用认证器的扫描二维码功能就可以一键导入密钥了。

生成密钥

这里以 python 为例,先安装以下依赖。

pip install pyotp
pip install qrcode

以下是示例代码。

import pyotp
import qrcode

# 生成密钥,需要将这个密钥保存到数据库中,并且和当前账户绑定起来。
secret_key = pyotp.random_base32()
# ===> ZPASQ6I4N6YVLJFV3A3PDJ7RBYWEUROX

# 为指定的密钥创建 OTP 生成器,用来生成一次性密码。
totp = pyotp.TOTP(secret_key)

# 为当前当前时间生成一个一次性密码,生成的密码默认有效期为 30 秒。
totp.now()
# ===> 277948

# 验证输入的密码是否在当前时间段有效,用于服务器验证用户输入的密码是否正确。
totp.verify("277948")
# ===> True
# 30 秒后
totp.verify("277948")
# ===> False

# 为密钥生成一个二维码,以便用户可以使用认证器扫描二维码来直接导入密钥。
qr = qrcode.make(totp.provisioning_uri("example@example.com", "YourAppName"))
qr.save("qrcode.png")

在 Java 中的例子如下。

先引入以下依赖。

<dependency>
    <groupId>dev.samstevens.totp</groupId>
    <artifactId>totp</artifactId>
    <version>1.7.1</version>
</dependency>

示例代码如下:

// 生成密钥
SecretGenerator secretGenerator = new DefaultSecretGenerator();
String secret = secretGenerator.generate();
// ===> 4PVVKLZ6IUXYEASJVY2QJRL444FOGUYE

// 生成二维码图片
QrData data = new QrData.Builder()
        .label("example@example.com")
        .secret(secret)
        .issuer("AppName")
        .build();
QrGenerator generator = new ZxingPngQrGenerator();
byte[] imageData = generator.generate(data);
String mimeType = generator.getImageMimeType();    // image/png

// 验证密码
TimeProvider timeProvider = new SystemTimeProvider();
CodeGenerator codeGenerator = new DefaultCodeGenerator();
CodeVerifier verifier = new DefaultCodeVerifier(codeGenerator, timeProvider);
boolean successful = verifier.isValidCode("4PVVKLZ6IUXYEASJVY2QJRL444FOGUYE", "504745");
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值