TOTP双因素认证(2FA)php简单实现

TOTP身份验证的工作原理基于时间戳和密钥。用户需要在设置阶段将密钥与相应的身份验证器进行绑定。通常,用户会在需要使用TOTP动态验证码的APP或网站上获得一个密钥,然后将该密钥添加到TOTP验证器工具上。验证器会根据当前的时间戳和密钥生成一个一次性密码(通常是6位数字),用户需要将这个密码输入到需要验证的系统中以完成身份验证。

1、针对某个登录用户生成秘钥

php 复制代码
<?php
//生成32位的秘钥
function generateSecret($length = 32) {
    $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; // Base32 字符集
    $secret = '';
    for ($i = 0; $i < $length; $i++) {
        $secret .= $characters[random_int(0, strlen($characters) - 1)];
    }
    return $secret;
}

$secret = generateSecret(); // 用户的唯一 Secret
echo "Secret Key: $secret";

2、生成某个登录用户需要绑定到Authenticator的链接(二维码形式显示)

php 复制代码
<?php
function generateQRCodeUrl($appName, $userEmail, $secret) {
    $issuer = urlencode($appName);
    $email = urlencode($userEmail);
    return "otpauth://totp/{$issuer}:{$email}?secret={$secret}&issuer={$issuer}";
}

$appName = "xxx-test";//在app列表中显示的名称
$userEmail = "xxx.xxx@gmail.com";
$secret='4IRT6WN2RHWZHJ4ZOO2POMYB6W43FQ7G';
$qrCodeUrl = generateQRCodeUrl($appName, $userEmail, $secret);
echo $qrCodeUrl;//当前链接生成为二维码的链接
//echo '<img src="' . $qrCodeUrl . '" alt="QR Code">';

3、登录的时候验证用户输入的code是否正确

php 复制代码
<?php
/**
 * 生成动态验证码(验证用)
 */
function getOtp($secret, $timeSlice = null) {
    if ($timeSlice === null) {
        $timeSlice = floor(time() / 30); // 当前时间戳除以30秒
    }

    $secretKey = base32Decode($secret); // 解码 Base32 密钥
    $time = pack('N*', 0) . pack('N*', $timeSlice); // 将时间戳转换为 64 位二进制

    // 使用 HMAC-SHA1 计算哈希值
    $hmac = hash_hmac('sha1', $time, $secretKey, true);

    // 截取动态偏移量
    $offset = ord(substr($hmac, -1)) & 0x0F;
    $binary = (ord($hmac[$offset]) & 0x7F) << 24 |
        (ord($hmac[$offset + 1]) & 0xFF) << 16 |
        (ord($hmac[$offset + 2]) & 0xFF) << 8 |
        (ord($hmac[$offset + 3]) & 0xFF);

    // 生成6位数字验证码
    return str_pad($binary % pow(10, 6), 6, '0', STR_PAD_LEFT);
}

function base32Decode($base32) {
    $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    $base32 = strtoupper($base32);
    $bits = '';
    foreach (str_split($base32) as $char) {
        $bits .= str_pad(decbin(strpos($characters, $char)), 5, '0', STR_PAD_LEFT);
    }
    $bytes = '';
    foreach (str_split($bits, 8) as $byte) {
        $bytes .= chr(bindec($byte));
    }
    return $bytes;
}

// $otp = getOtp($secret);
// echo "Generated OTP: $otp".PHP_EOL;
//验证方法
function verifyOtp($secret, $userInput, $window = 1) {
    $timeSlice = floor(time() / 30);//TOTP 的核心是基于当前时间的30秒时间片。一个时间片的公式是
    for ($i = -$window; $i <= $window; $i++) {
        echo "OTP: " . getOtp($secret, $timeSlice + $i) . PHP_EOL;
        echo "$i:$window".PHP_EOL;
        if (getOtp($secret, $timeSlice + $i) === $userInput) {
            return true;
        }
    }
    return false;
}
//index.php 生成的secret
$secret='4IRT6WN2RHWZHJ4ZOO2POMYB6W43FQ7G';
$userInput = '927055'; // 用户输入的动态验证码
if (verifyOtp($secret, $userInput)) {
    echo "验证通过!";
} else {
    echo "验证码错误,请重试。";
}
相关推荐
挨踢攻城7 小时前
华为 | SD-WAN场景丢包类问题定位
网络·华为·php·hcie·hcia·hcip·厦门微思网络
fakaifa12 小时前
【最新版】CRMEB Pro版v3.4系统源码全开源+PC端+uniapp前端+搭建教程
人工智能·小程序·uni-app·php·crmeb·源码下载·crmebpro
lingggggaaaa16 小时前
小迪安全v2023学习笔记(六十二讲)—— PHP框架反序列化
笔记·学习·安全·web安全·网络安全·php·反序列化
Q_Q19632884751 天前
python的电影院座位管理可视化数据分析系统
开发语言·spring boot·python·django·flask·node.js·php
Ashlee_code1 天前
香港券商智能櫃台系統技術解決方案——融合跨境清算與AI風控,助力券商把握滬港雙市爆發機遇**
java·科技·金融·重构·架构·系统架构·php
nightunderblackcat1 天前
进阶向:人物关系三元组,解锁人物关系网络的钥匙
开发语言·python·开源·php
向日葵.2 天前
fastdds.ignore_local_endpoints 属性
服务器·网络·php
dog2502 天前
难以超越的 TCP AIMD
网络协议·tcp/ip·php
檀越剑指大厂2 天前
【Linux系列】如何在 Linux 服务器上快速获取公网
linux·服务器·php
搬砖魁首2 天前
密码学系列 - 零知识证明(ZKP) - 多种承诺方案
密码学·零知识证明·pcs·zkp·承诺方案