简单且安全的通用OTP,OCRA (RFC6287),TOTP (RFC6238) & HOTP (RFC4226)解决方案!

4.01.3 2024-08-03 07:09 UTC

README

Security & Standards Codacy Badge Packagist Downloads (custom server) License: MIT Packagist Version Packagist PHP Version GitHub code size in bytes

简单但安全的AIO OTP解决方案。支持:

  • 通用OTP(无存储OTP解决方案)
  • TOTP (RFC6238)
  • HOTP (RFC4226)
  • OCRA (RFC6287)

目录

先决条件

语言:PHP 8.2+

安装

composer require infocyph/otp

为什么选择这个库?

TOTP & HOTP

  • 使用离线二维码生成器(不再暴露您的秘密在线)
  • 时间安全的Base32编码(30秒有效期意味着30秒)

通用OTP

  • 无需为用户信息分配额外的存储/数据库(只需构建一个唯一的签名)

OCRA

  • PHP中为数不多的实现之一,易于使用

用法

HOTP (RFC4226)

  • 生成密钥
$secret = \Infocyph\OTP\HOTP::generateSecret();
  • 为密钥 $secret 生成二维码图像(SVG格式)
// supports digit count in 2nd parameter, recommended to be either 6 or 8 (default 6)
(new \Infocyph\OTP\HOTP($secret))
// only required if the counter is being imported from another system or if it is old, & for QR only
->setCounter(3)
// default is sha1; Caution: many app (in fact, most of them) have algorithm limitation
->setAlgorithm('sha256') 
// or `getProvisioningUri` just to get the URI
->getProvisioningUriQR('TestName', 'abc@def.ghi'); 

getProvisioningUriQR & getProvisioningUri 接受第三个参数,其中它接受参数数组 ['algorithm', 'digits', 'period', 'counter']。您可能会遇到的问题,与URI/图像有关,大多数OTP生成器可能不支持所有这些选项。在这种情况下,传递一个空数组将删除所有可选键,或者您可以选择性地传递所需的参数。此外,您还可以在第四个参数中传递其他参数以反映在URI字符串或QR图像中。但请注意,客户端应用程序可能不支持这些参数。

  • 为给定的计数器获取当前的OTP
$counter = 346;
$otp = (new \Infocyph\OTP\HOTP($secret))->getOTP($counter);
  • 验证
(new \Infocyph\OTP\HOTP($secret))->verify($otp,$counter);

TOTP (RFC6238)

  • 生成密钥
$secret = \Infocyph\OTP\TOTP::generateSecret();
  • 为密钥 $secret 生成二维码图像(SVG格式)
// supports digit count in 2nd parameter, recommended to be either 6 or 8 (default 6)
(new \Infocyph\OTP\TOTP($secret))
// default is sha1; Caution: many app (in fact, most of them) have algorithm limitation
->setAlgorithm('sha256') 
// or `getProvisioningUri` just to get the URI
->getProvisioningUriQR('TestName', 'abc@def.ghi'); 

getProvisioningUriQR & getProvisioningUri 接受第三个参数,其中它接受参数数组 ['algorithm', 'digits', 'period', 'counter']。您可能会遇到的问题,与URI/图像有关,大多数OTP生成器可能不支持所有这些选项。在这种情况下,传递一个空数组将删除所有可选键,或者您可以选择性地传递所需的参数。此外,您还可以在第四个参数中传递其他参数以反映在URI字符串或QR图像中。但请注意,客户端应用程序可能不支持这些参数。

  • 为给定的计数器获取当前的OTP
$counter = 346;
$otp = (new \Infocyph\OTP\TOTP($secret))->getOTP($counter);
// or get OTP for another specified epoch time
$otp = (new \Infocyph\OTP\TOTP($secret))->getOTP(1604820275);
  • 验证
(new \Infocyph\OTP\TOTP($secret))->verify($otp);
// or verify for a specified time
(new \Infocyph\OTP\TOTP($secret))->verify($otp, 1604820275);

在第三个参数 (bool) 上,它支持启用宽容度。如果启用,它还将检查最后一段生成的OTP。

通用OTP

  • 启动
/**
* Param 1 is OTP length (default 6)
* Param 2 is validity in seconds (default 30)
* Param 3 is retry count on failure (default 3)
*/
$otpInstance = new \Infocyph\OTP\OTP(4, 60, 2);
  • 生成并获取OTP
$otp = $otpInstance->generate('an unique signature for a cause');
  • 验证OTP
$otpInstance->verify('an unique signature for a cause', $otp);

在第三个参数设置为false的情况下 将保留记录直到OTP被验证或过期。默认情况下,将保留记录直到密钥名匹配或OTP被验证或过期

  • 删除记录
$otpInstance->delete('an unique signature for a cause');
  • 刷新所有现有的OTP(如果有的话)
$otpInstance->flush()

通用OTP使用 临时位置 进行存储,请确保您有适当的访问权限

OCRA (RFC6287)

// Example usage:
$sharedKey = 'mySecretKey'; // Replace with your actual shared key (binary format)
$challenge = '123456'; // Replace with your challenge value
$counter = 0; // Replace with the appropriate counter value

// Create an OCRA instance
$suite = new \Infocyph\OTP\OCRA('OCRA-1:HOTP-SHA1-6:C-QN08', $sharedKey);

// If the OCRA suite supports session, set the session
$suite->setSession('...');

// If the OCRA suite supports time format, set the time
$suite->setTime(new \DateTime());

// If the OCRA suite supports pin, set the pin
$suite->setPin('...');

// Generate the OCRA value
$suite->generate($challenge, $counter);

构建OCRA套件

根据当前的RFC6287,示例字符串应采用以下格式

OCRA-1:HOTP-SHA1-6:C-QN08-PSHA1

OCRA-1:HOTP- 固定为当前文档。

  • SHA1是加密哈希函数。(支持的:SHA1,SHA256,SHA512)
  • 6是生成OTP的位数。(支持的:0,4-10)
  • C表示计数器支持(可选)
  • QN08表示模式(可以是QNxx,QAxx,QHxx之一)
  • 下一部分是可选的,有些复杂
    • PSHA1表示用于PIN支持的哈希函数(可以是PSHA1,PSHA256,PSHA512之一)
    • S(不在示例中)表示会话长度(3位数)
    • T(不在示例中)表示时间格式,如下表所示

支持

遇到麻烦?创建一个问题!

参考资料