前言:2FA的特点
个人理解:1、不用担心用户验证码的外泄,因为验证码每30s都会改变。2、获取验证码非常的简单,有很多工具。3、无需网络请求,直接本地就可以校验。4、最重要的是,你需要确保2FA的secret(相当于密钥)的安全,不能让外人知道。
1、强化账户安全:2FA提供了额外的安全层,使攻击者更难以入侵用户账户。即使攻击者获得了用户的密码,仍然需要第二个因素才能成功登录。
2、双重身份验证:2FA要求用户提供两个不同的身份验证因素,通常是"知道"、"拥有"和"是"这三个类别中的两个。常见的因素包括密码、手机验证码、指纹、面部识别等。
3、防止密码泄露:2FA提供了一种方式来应对密码泄露的风险。即使密码被泄露,攻击者仍然需要第二个因素才能成功登录。
4、动态密码生成:2FA通常使用动态密码生成器来生成一次性密码。这种密码在一段时间后会过期,增加了安全性。
5、灵活性和可定制性:2FA可以根据不同的需求进行定制。可以选择不同的身份验证因素,设置验证因素的顺序,并根据需要调整验证的强度。
6、广泛支持:2FA已经得到广泛支持,并在许多平台和服务中得到应用,包括社交媒体、电子邮件服务、银行和金融机构等。
1、Android使用的语言:Java
2、导入库
因为一些原因,使用 Base32 解码密钥时,少部分工具,你可能使用错误,造成最后的验证码错误
implementation 'commons-codec:commons-codec:1.15'
注意:可以使用自己原有的解码工具,只要可以生成正确的验证码就行
3、验证码校验类
import org.apache.commons.codec.binary.Base32;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class TwoFactorAuthenticator {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final int DIGITS = 6;
private static final int TIME_STEP_SECONDS = 30;
public static boolean validateTwoFactorCode(String secretKey, String code) {
long timeStep = System.currentTimeMillis() / 1000 / TIME_STEP_SECONDS; // 当前时间戳除以时间步长(30秒)
long counter = timeStep;
String generatedCode = generateCode(secretKey, counter);
System.out.println("Bin Password->code->" + code);
System.out.println("Bin Password->generatedCode->" + generatedCode);
if (generatedCode.equals(code)) {
return true;
}
return false;
}
private static String generateCode(String secretKey, long counter) {
byte[] keyBytes = new Base32().decode(secretKey);
byte[] counterBytes = longToBytes(counter);
try {
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
byte[] hash = mac.doFinal(counterBytes);
int offset = hash[hash.length - 1] & 0xF;
int truncatedHash = hashToInt(hash, offset) & 0x7FFFFFFF;
int pinValue = truncatedHash % (int) Math.pow(10, DIGITS);
return String.format("%0" + DIGITS + "d", pinValue);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
private static byte[] longToBytes(long value) {
byte[] result = new byte[8];
for (int i = 7; i >= 0; i--) {
result[i] = (byte) (value & 0xFF);
value >>= 8;
}
return result;
}
private static int hashToInt(byte[] bytes, int offset) {
int value = 0;
for (int i = offset; i < offset + 4; i++) {
value <<= 8;
value |= bytes[i] & 0xFF;
}
return value;
}
}
4、使用示例
Boolean result = TwoFactorAuthenticator.validateTwoFactorCode(GLOBAL_PASSWORD_KEY,password);
GLOBAL_PASSWORD_KEY:二次验证码的secret(相当于加密密钥)
password:用户输入的密码
result:验证返回的结果,如果正确,返回true,反正,返回false