samyoul / u2f-php-server
FIDO U2F 注册和身份验证的 Server 端处理类
Requires
- ext-openssl: *
This package is not auto-updated.
Last update: 2024-09-14 18:53:18 UTC
README
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
内容
安装
composer require samyoul/u2f-php-server
要求
在开始使用此库之前,您需要了解一些 注意事项
- OpenSSL 您需要至少 OpenSSL 1.0.0 或更高版本。
- 客户端处理 您需要能够与某种设备进行通信。
- HTTPS URL 这非常重要,没有 HTTPS,U2F 将无法工作。
- 数据存储 您需要某种类型的数据存储,以存储所有已注册的 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 的服务器进行通信。
- 谷歌已经解决了这部分问题: https://github.com/google/u2f-ref-code/blob/master/u2f-gae-demo/war/js/u2f-api.js
- 用户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%必要,但会使您的应用程序更加安全。
待办事项:描述
工作流程
注册流程
- 用户导航到应用程序中的第二个因素身份验证页面。
... 待办事项:添加注册流程的其余部分 ...
身份验证流程
- 用户像平时一样导航到他们的登录页面,提交用户名和密码。
- 服务器收到POST请求认证数据,执行正常的用户名 + 密码验证
- 在成功认证后,应用程序检查是否需要第二个因素认证。我们将假设需要,否则用户将在这个阶段直接登录。
- 应用程序从应用程序数据存储库中获取用户的已注册签名:
$registrations
。 - 应用程序获取其ID,通常是应用程序可访问的域名:
$appId
- 应用程序调用
U2F::makeAuthentication($registrations, $appId)
,该方法返回一个SignRequest
对象数组:$authenticationRequest
。 - 应用程序将数组JSON编码并传递数据到视图中
- 当浏览器加载页面时,JavaScript将触发
u2f.sign(authenticationRequest, function(data){ // 回调逻辑 })
函数 - 视图将使用JavaScript / 浏览器轮询主机机的端口以查找FIDO U2F设备
- 一旦找到HID,JavaScript / 浏览器将发送带数据的签名请求
- HID将提示用户授权签名请求
- 在成功后,HID返回认证数据
- JavaScript接收HID返回的数据并将其传递到服务器
- 应用程序将返回数据传递给
U2F::authenticate($authenticationRequest, $registrations, $authenticationResponse)
方法 - 如果该方法返回一个注册项且未抛出异常,则认证完成。
- 设置用户会话,通知用户成功,并重定向他们。
示例代码
有关此存储库的完整工作代码示例,请参阅专门的示例存储库
您也可以使用以下方式安装它
$ git clone https://github.com/Samyoul/U2F-php-server-examples.git
$ cd u2f-php-server-examples
$ composer install
兼容性代码
您只需在每个安装中调用此方法一次,并且仅在调试类给您带来意外错误的情况下。此方法调用将检查您的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