itrack/csrf

此包最新版本(1.1)没有可用的许可信息。

易于使用的跨站请求伪造保护。

1.1 2019-09-25 10:59 UTC

This package is not auto-updated.

Last update: 2024-09-16 00:34:41 UTC


README

这个库是一个简单的签名生成器,用于通过使用已签名的令牌保护表单提交免受跨站请求伪造。它不需要在服务器端存储有效的令牌,因此是无状态的。

安装

composer require itrack/csrf

简单用法

$secret = '948thksehbf23fnoug2p4g2o...'; // well chosen secret
$signer = new \Itrack\CSRF\SignatureGenerator($secret);

if ($_POST) {
    if (!$signer->validateSignature($_POST['_token'])) {
        header('HTTP/1.0 400 Bad Request');
        exit;
    }
}
<form action="" method="post">
    <?php printf('<input type="hidden" name="_token" value="%s">', $signer->getSignature()); ?>
    ...
    <input type="submit" value="Submit">
</form>

SignatureGenerator 需要每次使用相同的密钥进行实例化。要生成已签名的令牌,只需调用 SignatureGenerator::getSignature 并将值嵌入到隐藏表单字段中。表单提交时,使用 SignatureGenerator::validateSignature 验证此令牌。

时间限制的有效性

签名包含生成时的时间戳。这可以用来在一段时间后使签名过期。时间戳是签名生成过程的一部分,无法更改。默认情况下,签名在几小时后过期(默认值请参阅 SignatureGenerator::$validityWindow)。您可以使用 SignatureGenerator::setValidityWindow 设置自己的有效期窗口。

$signer->setValidityWindow(time() - 3600);
$signer->setValidityWindow('-1 hour');
$signer->setValidityWindow(new DateTime('-1 hour'));

该方法接受整数 UNIX 时间戳、由 strtotime 评估的字符串或 DateTime 实例。任何早于设置时间戳的签名都将被视为已过期。默认超时应该提供一个合理的值,以确保签名最终会过期,而不会让慢速用户感到沮丧。根据您的需求进行调整,使其更紧密或更宽松。

添加数据

除了用作防止表单字段注入外,签名还可以用于与特定用户相关联。可以使用 SignatureGenerator::addValueSignatureGenerator::addKeyValue 添加数据到签名生成过程中。

$signer->addValue('foo');
$signer->addKeyValue('bar', 'baz');

签名只有在生成令牌和验证令牌时添加了相同的数据时才有效。要防止表单字段注入,应使用 SignatureGenerator::addValue 添加您期望在提交的表单中收到的所有 <input> 元素的名称。您希望与签名相关联的任何其他数据,如用户 ID,应使用 SignatureGenerator::addKeyValue 添加。

例如,在生成令牌时

$signer = new \Itrack\CSRF\SignatureGenerator($secret);

// including user id in signature
// 'userid' is an arbitrarily chosen key name
$signer->addKeyValue('userid', $_SESSION['User']['id']);

// including names of valid form fields in signature
$signer->addValue('_token');
$signer->addValue('firstname');
$signer->addValue('lastname');
<form action="" method="post">
    <?php printf('<input type="hidden" name="_token" value="%s">', $signer->getSignature()); ?>
    <input type="text" name="firstname">
    <input type="text" name="lastname">
    <input type="submit" value="Submit">
</form>

在验证令牌时,使用提交的表单字段作为验证的一部分

$signer = new \Itrack\CSRF\SignatureGenerator($secret);

// including user id in signature validation
$signer->addKeyValue('userid', $_SESSION['User']['id']);

// including submitted form fields in signature validation
foreach (array_keys($_POST) as $key) {
    $signer->addValue($key);
}

if (!$signer->validateSignature($_POST['_token'])) {
    // error
}

这样,如果任何不是原始签名部分的字段随表单一起提交,它将不会验证。如果您使用 JavaScript 动态添加表单字段,请小心操作。

注意

添加表单字段的缺点是,在生成签名和验证签名时都需要添加相同的表单字段。这需要同步预期和实际表单字段列表,如果不妥善处理,可能会快速导致代码重复。为了获得最佳结果,我建议将此库用作更大表单生成功能/类/库的一部分,该库处理此操作。

签名格式

签名使用 base64 编码,默认格式为

timestamp + ":" + token + ":" + signed token

其中

timestamp    = unsigned integer
token        = base64 encoded random value
signed token = base64 encoded hash

hash         = HMAC_SHA512(timestamp + token + data, secret)
data         = all added values

data 是排序的,因此添加值的顺序不重要。上面的描述省略了有关将数据放入哈希的确切格式的技术细节,请参阅源代码。

加密提供程序

一种替代的 CryptoProvider,它提供随机数源和哈希算法,可以在实例化 SignatureGenerator 时作为构造函数的第二个参数传递。请参考 ICryptoProvider.phpCryptoProvider.php

信息

基于 https://github.com/deceze/Kunststube-CSRFP