rollerworks/split-token

无侧通道的基于令牌的认证协议

v1.0.0-BETA2 2024-01-06 11:48 UTC

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。