samyoul/u2f-php-server

FIDO U2F 注册和身份验证的 Server 端处理类

v1.1.4 2018-10-26 12:43 UTC

This package is not auto-updated.

Last update: 2024-09-14 18:53:18 UTC


README

Latest Stable Version License

PHP 的 FIDO U2F 注册和身份验证的 Server 端处理。

保护您的在线账户,并保护您的数据,这是极其重要的,随着黑客技术的日益复杂,这一点越来越重要。FIDO 的 U2F 允许您添加一种简单且不引人注目的二次验证方法,使用户能够将硬件密钥与其账户链接。

U2F php 库系列

基本库

https://github.com/Samyoul/U2F-php-server

Fido 测试套件 (UTD)

https://github.com/Samyoul/U2F-php-UTD

框架

Laravel https://github.com/Samyoul/U2F-Laravel-server

Yii https://github.com/Samyoul/U2F-Yii-server

CodeIgniter https://github.com/Samyoul/U2F-CodeIgniter-server

内容

  1. 安装
  2. 要求
    1. OpenSSL
    2. 客户端魔法
    3. HTTPS 和 SSL
  3. 术语
  4. 推荐的数据存储结构
  5. 工作流程
    1. 注册流程
    2. 身份验证流程
  6. 示例代码
    1. 兼容性检查
    2. 注册代码
    3. 身份验证代码
  7. 框架
    1. Laravel
    2. Yii
    3. CodeIgniter
  8. 许可
  9. 致谢

安装

composer require samyoul/u2f-php-server

要求

在开始使用此库之前,您需要了解一些 注意事项

  1. OpenSSL 您需要至少 OpenSSL 1.0.0 或更高版本。
  2. 客户端处理 您需要能够与某种设备进行通信。
  3. HTTPS URL 这非常重要,没有 HTTPS,U2F 将无法工作。
  4. 数据存储 您需要某种类型的数据存储,以存储所有已注册的 U2F 用户(尽管如果您有一个用户身份验证系统,我假设您已经解决了这个问题)。

OpenSSL

此存储库需要 OpenSSL 1.0.0 或更高版本。有关安装 OpenSSL 的更多详细信息,请参阅 php 手册 https://php.ac.cn/manual/en/openssl.installation.php .

另请参阅 兼容性代码,以检查您是否已安装正确版本的 OpenSSL,并且不确定如何进行其他检查。

客户端(与 USB 设备通信的 JavaScript 魔法部分)

我的假设是,如果您正在寻找将 U2F 身份验证添加到 php 系统,那么您可能也正在寻找一些客户端处理。您有一个启用 U2F 的 USB 设备,您想让它与浏览器以及运行 php 的服务器进行通信。

  1. 谷歌已经解决了这部分问题: https://github.com/google/u2f-ref-code/blob/master/u2f-gae-demo/war/js/u2f-api.js
  2. 用户Mastahyeti创建了一个专门用于谷歌JavaScript客户端API的仓库:https://github.com/mastahyeti/u2f-api

HTTPS 和 SSL

为了使U2F工作,您的网站/服务必须使用HTTPS URL。没有HTTPS URL,您的代码将无法工作,因此请为您的localhost获取一个,为您的生产环境获取一个。https://letsencrypt.openssl.ac.cn/ 基本上加密所有内容。

术语

HID人机接口设备,例如USB设备像这些东西

推荐的数据存储结构

您不需要严格遵循此结构,但您需要将注册数据与用户关联起来。您还需要存储密钥句柄、公钥和证书,计数器并非100%必要,但会使您的应用程序更加安全。

待办事项:描述

工作流程

注册流程

  1. 用户导航到应用程序中的第二个因素身份验证页面。

... 待办事项:添加注册流程的其余部分 ...

身份验证流程

  1. 用户像平时一样导航到他们的登录页面,提交用户名和密码。
  2. 服务器收到POST请求认证数据,执行正常的用户名 + 密码验证
  3. 在成功认证后,应用程序检查是否需要第二个因素认证。我们将假设需要,否则用户将在这个阶段直接登录。
  4. 应用程序从应用程序数据存储库中获取用户的已注册签名:$registrations
  5. 应用程序获取其ID,通常是应用程序可访问的域名:$appId
  6. 应用程序调用U2F::makeAuthentication($registrations, $appId),该方法返回一个SignRequest对象数组:$authenticationRequest
  7. 应用程序将数组JSON编码并传递数据到视图中
  8. 当浏览器加载页面时,JavaScript将触发u2f.sign(authenticationRequest, function(data){ // 回调逻辑 })函数
  9. 视图将使用JavaScript / 浏览器轮询主机机的端口以查找FIDO U2F设备
  10. 一旦找到HID,JavaScript / 浏览器将发送带数据的签名请求
  11. HID将提示用户授权签名请求
  12. 在成功后,HID返回认证数据
  13. JavaScript接收HID返回的数据并将其传递到服务器
  14. 应用程序将返回数据传递给U2F::authenticate($authenticationRequest, $registrations, $authenticationResponse)方法
  15. 如果该方法返回一个注册项且未抛出异常,则认证完成。
  16. 设置用户会话,通知用户成功,并重定向他们。

示例代码

有关此存储库的完整工作代码示例,请参阅专门的示例存储库

您也可以使用以下方式安装它

$ git clone https://github.com/Samyoul/U2F-php-server-examples.git
$ cd u2f-php-server-examples
$ composer install 
  1. 兼容性代码
  2. 注册代码
    1. 步骤1:启动
    2. 步骤2:与HID通信
    3. 步骤3:验证和存储
  3. 身份验证代码
    1. 步骤1:启动
    2. 步骤2:与HID通信
    3. 步骤3:验证

兼容性代码

您只需在每个安装中调用此方法一次,并且仅在调试类给您带来意外错误的情况下。此方法调用将检查您的OpenSSL版本,并确保它至少为1.0.0。

<?php

require('vendor/autoload.php');
use Samyoul\U2F\U2FServer\U2FServer as U2F;

var_dump(U2F::checkOpenSSLVersion());

注册代码

注册步骤1

启动注册过程

我们假设用户已成功认证并希望注册。

<?php

require('vendor/autoload.php');
use Samyoul\U2F\U2FServer\U2FServer as U2F;

session_start();

// This can be anything, but usually easier if you choose your applications domain and top level domain.
$appId = "yourdomain.tld";

// Call the makeRegistration method, passing in the app ID
$registrationData = U2F::makeRegistration($appId);

// Store the request for later
$_SESSION['registrationRequest'] = $registrationData['request'];

// Extract the request and signatures, JSON encode them so we can give the data to our javaScript magic
$jsRequest = json_encode($registrationData['request']);
$jsSignatures = json_encode($registrationData['signatures']);

// now pass the data to a fictitious view.
echo View::make('template/location/u2f-registration.html', compact("jsRequest", "jsSignatures"));

注册步骤2

客户端,与USB通信

非AJAX客户端端U2F密钥令牌注册。当然,您可以在应用程序中使用AJAX,但使用AJAX和回调来演示线性过程更容易。

<html>
<head>
    <title>U2F Key Registration</title>
</head>
<body>
    <h1>U2F Registration</h1>
    <h2>Please enter your FIDO U2F device into your computer's USB port. Then confirm registration on the device.</h2>
    
    <div style="display:none;">
        <form id="u2f_submission" method="post" action="auth/u2f-registration/confirm">
            <input id="u2f_registration_response" name="registration_response" value="" />
        </form>
    </div>
    
<script type="javascript" src="https://raw.githubusercontent.com/google/u2f-ref-code/master/u2f-gae-demo/war/js/u2f-api.js"></script>
<script>
    setTimeout(function() {
    
        // A magic JS function that talks to the USB device. This function will keep polling for the USB device until it finds one.
        u2f.register([<?php echo $jsRequest ?>], <?php echo $jsSignatures ?>], function(data) {
           
            // Handle returning error data
            if(data.errorCode && errorCode != 0) {
                alert("registration failed with error: " + data.errorCode);
                // Or handle the error however you'd like. 
                
                return;
            }
    
            // On success process the data from USB device to send to the server
            var registration_response = JSON.stringify(data);
            
            // Get the form items so we can send data back to the server
            var form = document.getElementById('u2f_submission');
            var response = document.getElementById('u2f_registration_response');
            
            // Fill and submit form.
            response.value = JSON.stringify(registration_response);
            form.submit();
        });
    }, 1000);
</script>
</body>
</html>

注册步骤3

验证和密钥存储

这是注册的最后阶段。验证注册响应数据与原始请求数据。

<?php

require('vendor/autoload.php');
use Samyoul\U2F\U2FServer\U2FServer as U2F;

session_start();

// Fictitious function representing getting the authenticated user object
$user = getAuthenticatedUser();

try {
    
    // Validate the registration response against the registration request.
    // The output are the credentials you need to store for U2F authentication.
    $validatedRegistration = U2F::register(
        $_SESSION['registrationRequest'],
        json_decode($_POST['u2f_registration_response'])
    );
    
    // Fictitious function representing the storing of the validated U2F registration data against the authenticated user. 
    $user->storeRegistration($validatedRegistration);
    
    // Then let your user know what happened
    $userMessage = "Success";
} catch( Exception $e ) {
    $userMessage = "We had an error: ". $e->getMessage();
}

//Fictitious view.
echo View::make('template/location/u2f-registration-result.html', compact('userMessage'));

身份验证代码

认证步骤1

启动认证过程

我们假设用户已成功认证,并且之前已注册使用FIDO U2F。

<?php
    
require('vendor/autoload.php');
use Samyoul\U2F\U2FServer\U2FServer as U2F;

session_start();

// Fictitious function representing getting the authenticated user object
$user = getAuthenticatedUser();

// Fictitious function, get U2F registrations associated with the user
$registrations = $user->U2FRegistrations();

// This can be anything, but usually easier if you choose your applications domain and top level domain.
$appId = "yourdomain.tld";

// Call the U2F makeAuthentication method, passing in the user's registration(s) and the app ID
$authenticationRequest = U2F::makeAuthentication($registrations, $appId);

// Store the request for later
$_SESSION['authenticationRequest'] = $authenticationRequest;

// now pass the data to a fictitious view.
echo View::make('template/location/u2f-authentication.html', compact("authenticationRequest"));

认证步骤 2

客户端,与USB通信

非AJAX客户端端U2F密钥令牌的认证。当然,您可以在您的应用程序中使用AJAX,但使用AJAX和回调来展示线性过程更容易。

<html>
<head>
    <title>U2F Key Authentication</title>
</head>
<body>
    <h1>U2F Authentication</h1>
    <h2>Please enter your FIDO U2F device into your computer's USB port. Then confirm authentication on the device.</h2>
    
    <div style="display:none;">
        <form id="u2f_submission" method="post" action="auth/u2f-authentication/confirm">
            <input id="u2f_authentication_response" name="authentication_response" value="" />
        </form>
    </div>

    <script type="javascript" src="https://raw.githubusercontent.com/google/u2f-ref-code/master/u2f-gae-demo/war/js/u2f-api.js"></script>
    <script>
    setTimeout(function() {
        
        // Magic JavaScript talking to your HID
        u2f.sign(<?php echo $authenticationRequest; ?>, function(data) {
            
            // Handle returning error data
            if(data.errorCode && errorCode != 0) {
                alert("Authentication failed with error: " + data.errorCode);
                // Or handle the error however you'd like. 
                
                return;
            }
    
            // On success process the data from USB device to send to the server
            var authentication_response = JSON.stringify(data);
            
            // Get the form items so we can send data back to the server
            var form = document.getElementById('u2f_submission');
            var response = document.getElementById('u2f_authentication_response');
            
            // Fill and submit form.
            response.value = JSON.stringify(authentication_response);
            form.submit();
        });
    }, 1000);
    </script>
</body>
</html>

认证步骤 3

验证

这是认证的最后阶段。将认证响应数据与原始请求数据进行验证。

<?php

require('vendor/autoload.php');
use Samyoul\U2F\U2FServer\U2FServer as U2F;

session_start();

// Fictitious function representing getting the authenticated user object
$user = authenticatedUser();

// Fictitious function, get U2F registrations associated with the user
$registrations = $user->U2FRegistrations();

try {
    
    // Validate the authentication response against the registration request.
    // The output are the credentials you need to store for U2F authentication.
    $validatedAuthentication = U2F::authenticate(
        $_SESSION['authenticationRequest'],
        $registrations,
        json_decode($_POST['u2f_authentication_response'])
    );
    
    // Fictitious function representing the updating of the U2F token count integer. 
    $user->updateU2FRegistrationCount($validatedAuthentication);
    
    // Then let your user know what happened
    $userMessage = "Success";
} catch( Exception $e ) {
    $userMessage = "We had an error: ". $e->getMessage();
}

//Fictitious view.
echo View::make('template/location/u2f-authentication-result.html', compact('userMessage'));

再次提醒,如果您只想下载一些示例代码进行实验,请安装此存储库中为该存储库编写的完整工作代码示例,请参阅专门的示例存储库

您也可以使用以下方式安装它

$ git clone https://github.com/Samyoul/U2F-php-server-examples.git
$ cd u2f-php-server-examples
$ composer install 

框架

Laravel 框架

请参阅专门的存储库: https://github.com/Samyoul/U2F-Laravel-server

安装

composer require u2f-laravel-server

Yii 框架

请参阅专门的存储库: https://github.com/Samyoul/U2F-Yii-server

安装

composer require u2f-yii-server

CodeIgniter 框架

请参阅专门的存储库: https://github.com/Samyoul/U2F-CodeIgniter-server

安装

composer require u2f-codeigniter-server

没有找到您的框架?

您的喜欢的PHP框架不在此列表中?开始编写代码,提交拉取请求,并将您的框架扩展包括在这里。

许可

该存储库采用BSD许可证。 在此处阅读详细信息

致谢

此存储库最初基于Yubico php-u2flib-server https://github.com/Yubico/php-u2flib-server