krixon/multi-factor-auth

PHP7的多种因素认证库

0.5.1 2020-02-13 09:24 UTC

README

Build Status Coverage Status Code Climate Latest Stable Version Latest Unstable Version License

SensioLabsInsight

一个用于生成和验证在多种因素认证系统中使用的代码的库。

特性

  • 基于时间的(TOTP)代码生成和验证。
  • 基于事件的(HOTP)代码生成和验证。
  • 生成条形码以简化客户端设置。

此库实现了以下RFC

它已与以下多种因素认证工具进行了测试

先决条件

  • PHP 7.1+

安装

通过Composer安装

要使用Composer安装此库,请运行以下命令

$ composer require krixon/multi-factor-auth

您可以在Packagist上看到此库。

从源代码安装

# HTTP
$ git clone https://github.com/krixon/multi-factor-auth.git
# SSH
$ git clone git@github.com:krixon/multi-factor-auth.git

快速开始

假设您有一个服务器端应用程序,您想使用多种因素认证来保护它。

涉及三个主要步骤

  1. 生成一个在服务器和用户之间共享的秘密。
  2. 使用共享秘密配置客户端应用程序(如Google Authenticator)。
  3. 当用户需要认证时,验证客户端应用程序生成的代码。

此库使这些步骤变得简单。

快速开始的方法是创建一个新的MultiFactorAuth类的实例。这个构造函数接受多个参数,但提供了一个静态工厂,它使用合理的默认值创建实例。您需要提供的只是“发行者”字符串。这只是一个标签,用于标识管理用户账户的提供者或服务 - 即您的应用程序。

<?php

use Krixon\MultiFactorAuth\MultiFactorAuth;

$mfa = MultiFactorAuth::default('Example Issuer');

接下来,您需要生成共享秘密。默认情况下,下面的代码将生成一个160位的base32编码字符串

$secret = $mfa->generateSecret();

为了使用户能够配置他们的客户端应用程序,他们需要输入刚才生成的秘密。通常,用户的客户端应用程序将运行在他们的手机上。手动输入160位的秘密当然是可以的,但我们可以通过为用户提供一个条形码来扫描来简化这个过程。此条形码包含配置客户端所需的所有信息。

在生成条形码时,您还必须提供一个账户标识符。这可以是任何字符串,使用户能够在他们的客户端应用程序中区分多个账户。一个好的值是用户的电子邮件地址。

$barcode = $mfa->generateTimeBasedBarcode($secret, 'jane.doe@example.com');

generateTimeBasedBarcode()方法返回一个Barcode实例。这可以用来最终渲染图像,例如在网页上

<img src="<?= $barcode->dataUri() ?>">

当用户扫描条形码后,应该提示他们输入一个可以验证的代码,以确定配置过程成功。

$verified = $mfa->verifyTimeBasedCode($code, $secret);

如果代码验证成功,则可以在服务器上安全地持久保存秘密,例如在数据库中。

从现在开始,当用户认证时,应该提示他们输入一个代码,以及他们的其他凭证,如用户名和密码。此代码应使用存储的共享秘密进行验证,如果验证失败,则拒绝认证。

生成备份代码

如果用户丢失了设备或无法生成代码,您可以允许他们通过预先生成的备份代码进行登录。基于事件(HOTP)的代码非常适合此用途。

以下示例生成了10个备份代码,用户可以将其写下或以其他方式存储。

use Krixon\MultiFactorAuth\Codec\Base32Codec;
use Krixon\MultiFactorAuth\MultiFactorAuth;

$mfa = MultiFactorAuth::default('Test Issuer');

// Secrets are expected to be in base32 by default for compatibility with Google Authenticator and similar apps.
// It is possible to use any encoding (including none). See below for more information.
$secret = (new Base32Codec())->encode('12345678901234567890');

 // Retrieve the real counter from the DB or wherever it is stored.
$counter = 42;

// $codes is an array of 10 strings, each 6 digits long.
$codes = $mfa->generateBackupCodes($secret, $counter, 10, 6);

foreach ($codes as $code) {
    // Do something with the backup code.
    // Generally you would salt and hash the code and store it in a database. These codes would be checked
    // against the one entered by the user (in addition to checking the current time or event-based code).
    echo "$code\n";
}

生成密钥

默认情况下,密钥是通过使用 RandomBytesSecretGenerator 生成的。这使用PHP的 random_bytes 函数生成加密安全的密钥。如果需要不同的方法,只需实现 SecretGenerator 接口。

RandomBytesSecretGenerator 接收一个 Codec 实例,该实例确定如何对生成的密钥进行编码。为了与Google Authenticator和类似的应用程序实现最大兼容性,密钥应使用base32编码,因此如果没有指定其他编码,则使用 Base32Codec

要生成密钥,可以直接使用 SecretGenerator,或者使用 MultiFactorAuth 门面。

$generator = new RandomBytesSecretGenerator();

// Generates a base32-encoded, 20 byte random secret.
$secret = $generator->generateSecret();

// Generates a base32-encoded, 30 byte random secret.
$secret = $generator->generateSecret(30);

// Generates a raw binary, 20 byte random secret.
$generator = new RandomBytesSecretGenerator(new PassThroughCodec());
$secret    = $generator->generateSecret(30);

// Generates a base32-encoded, 20 byte random secret.
$mfa    = MultiFactorAuth::default('Test Issuer');
$secret = $mfa->generateSecret();

沙盒

examples 目录中有一个简单的沙盒脚本,可用于生成密钥和条形码,以及验证客户端应用程序生成的代码。

可以使用PHP内置的web服务器运行沙盒。请确保指定正确的 examples 目录路径。

php -S localhost:8080 -t /path/to/krixon/multi-factor-auth/examples

现在可以访问 https://:8080/sandbox.php 使用沙盒。

待办事项