rollerworks / split-token
无侧通道的基于令牌的认证协议
Requires
- php: >=8.2
- paragonie/constant_time_encoding: ^2.6
- paragonie/hidden-string: ^2.0
- psr/clock: ^1.0
Requires (Dev)
- doctrine/instantiator: ^2.0
- phpunit/phpunit: ^10.4
- rollerscapes/standards: ^1.0
- symfony/clock: ^6.3
This package is auto-updated.
Last update: 2024-09-06 14:33:34 UTC
README
SplitToken提供了一种无侧通道的基于令牌的认证协议。
这种技术基于Split Tokens: 无侧通道的基于令牌的认证协议,最初由Paragon Initiative Enterprises提出。
基于SplitToken的认证最适合用于密码重置或单次单次登录。
虽然可行,但这种方法不建议作为OAuth或Json Web Tokens的替代品。
介绍
与传统的基于令牌的认证协议不同,SplitToken由两部分组成:用于查询的选择器和未用于查询的验证器。
-
选择器是一个24字节固定长度的随机字符串,用作标识符。您可以安全地为字段创建一个唯一的索引。
-
验证器作为密码使用,仅提供给用户,数据库只保存验证器的盐值(加密)散列。
此值的长度严重依赖于所使用的哈希算法,不应硬编码。
完整的令牌提供给用户或收件人,并作为组合标识符(选择器)和密码(验证器)使用。
注意:您绝不能以原样存储完整的令牌! 您只存储选择器,以及验证器的(加密)哈希。
安装
要安装此包,将rollerworks/split-token
添加到您的composer.json文件中
$ php composer.phar require rollerworks/split-token
现在,[Composer][composer]将自动下载所有必需的文件,并为您安装它们。
要求
PHP 8.1启用sodium扩展(从PHP 8开始默认启用)。
基本用法
<?php use Rollerworks\Component\SplitToken\Argon2SplitTokenFactory; // First, create the factory to generate a new SplitToken. // // Note: For unit testing it's highly recommended to use // the FakeSplitTokenFactory instead as cryptographic operations // can a little heavy. // Default configuration, shown here for clarity. $config = [ 'memory_cost' => \PASSWORD_ARGON2_DEFAULT_MEMORY_COST, 'time_cost' => \PASSWORD_ARGON2_DEFAULT_TIME_COST, 'threads' => \PASSWORD_ARGON2_DEFAULT_THREADS, ]; // Either a DateInterval or a DateInterval parsable-string $defaultLifeTime = null; $splitTokenFactory = new Argon2SplitTokenFactory(/*config: $config, */ $defaultLifeTime); // Optionally set PSR/Clock compatible instance // $splitTokenFactory->setClock(); // Step 1. Create a new SplitToken for usage $token = $splitTokenFactory->generate(); // The $authToken holds a \ParagonIE\HiddenString\HiddenString to prevent // leakage of this value. You need to cast this object to an actual string // at of usage. // // The $authToken is to be shared with the receiver (user) only. // The value is already encoded as base64 uri-safe string. // // // AGAIN, DO NOT STORE "THIS" VALUE IN THE DATABASE! Store the selector and verifier-hash instead. // $authToken = $token->token(); // Returns a \ParagonIE\HiddenString\HiddenString object // Indicate when the token must expire. Note that you need to clear the token from storage yourself. // Pass null (or leave this method call absent) to never expire the token (not recommended). // // If not provided uses "now" + $defaultLifeTime of the factory constructor. $authToken->expireAt(new \DateTimeImmutable('+1 hour')); // Now to store the token cast the SplitToken to a SplitTokenValueHolder object. // // Unlike SplitToken this class is final and doesn't hold the full-token string. // // Additionally you store the token with metadata (array only), // See the linked manual below for more information. $holder = $token->toValueHolder(); // Setting the token would look something like this. // UPDATE site_user // SET // recovery_selector = $holder->selector(), // recovery_verifier = $holder->verifierHash(), // recovery_expires_at = $holder->expiresAt(), // recovery_metadata = json_encode($holder->metadata()), // recovery_timestamp = NOW() // WHERE user_id = ... // ---- // Step 2. Reconstruct the SplitToken from a user provided string. // When the user provides the token verify if it's valid. // This will throw an exception of token is not of the expected length. $token = $splitTokenFactory->fromString($_GET['token']); // $result = SELECT user_id, recover_verifier, recovery_expires_at, recovery_metadata WHERE recover_selector = $token->selector() $holder = new SplitTokenValueHolder($token->selector(), $result['recovery_verifier'], $result['recovery_expires_at'], json_decode($result['recovery_metadata'], true)); if ($token->matches($holder)) { echo 'OK, you have access'; } else { // Note: Make sure to remove the token from storage. echo 'NO, I cannot let you do this John.'; }
使用选择器找到结果后,存储的验证器散列用于计算提供的验证器的匹配散列。然后以恒定时间比较这些值,以保护免受侧通道攻击。
另请参阅
错误处理
出于安全原因,SplitToken
仅对错误使用抛出通用运行时异常,而不抛出有关无效输入的详细异常。
发生错误时,验证器和完整令牌的内存分配将被清零,以防止在核心转储或未处理的异常期间泄露。
版本控制
为了透明度和对发布周期的洞察,并努力保持向后兼容性,此包尽可能遵循语义版本控制指南进行维护。
版本号将采用以下格式
<主要>.<次要>.<修补程序>
并遵循以下指南
- 破坏向后兼容性将增加主要版本(并重置次要版本和修补程序)
- 在不破坏向后兼容性的情况下添加新功能将增加次要版本(并重置修补程序)
- 错误修复和杂项更改将增加修补程序
有关SemVer的更多信息,请访问http://semver.org/。
谁在背后支持这个库?
此库由Sebastiaan Stok提供。
Split Token的想法最初由Paragon Initiative Enterprises提出。
许可协议
此包的源代码受Mozilla公共许可证(MPLv2.0许可)条款的约束。
可以安全地与任何其他许可证一起使用,包括MIT和GNU GPL。