itrack / csrf
易于使用的跨站请求伪造保护。
Requires
- php: >=7.0.0
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::addValue
和 SignatureGenerator::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.php
和 CryptoProvider.php
。