对于安全代码,请不要以这种方式生成令牌:$token = md5(uniqid(rand(), TRUE));
试试这个:
生成 CSRF 令牌
7 菲律宾比索
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];
旁注:我雇主的开源项目之一是向后移植和进入 PHP 5 项目的倡议。它是麻省理工学院授权的,可在Github和Composer上作为paragonie / random_compat。random_bytes()
random_int()
PHP 5.3+ (或使用 ext-mcrypt)
session_start();
if (empty($_SESSION['token'])) {
if (function_exists('mcrypt_create_iv')) {
$_SESSION['token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
} else {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
}
$token = $_SESSION['token'];
验证 CSRF 令牌
不要只使用甚至使用 hash_equals()
(仅限 PHP 5.6+,但可用于具有哈希兼容库的早期版本)。==
===
if (!empty($_POST['token'])) {
if (hash_equals($_SESSION['token'], $_POST['token'])) {
// Proceed to process the form data
} else {
// Log this as a warning and keep an eye on these attempts
}
}
进一步使用每表单令牌
您可以使用 hash_hmac()
进一步将令牌限制为仅可用于特定窗体。HMAC是一种特殊的键控哈希函数,即使使用较弱的哈希函数(例如MD5),也可以使用。但是,我建议改用 SHA-2 系列哈希函数。
首先,生成第二个令牌用作 HMAC 密钥,然后使用如下逻辑来呈现它:
<input type="hidden" name="token" value="<?php
echo hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
?>" />
然后在验证令牌时使用同余操作:
$calc = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
if (hash_equals($calc, $_POST['token'])) {
// Continue...
}
为一种形式生成的令牌不能在不了解 的情况下在另一个上下文中重用。使用单独的令牌作为 HMAC 密钥比刚刚放在页面上的令牌更重要。$_SESSION['second_token']
奖励:混合方法+树枝集成
任何使用 Twig 模板引擎的人都可以通过将此筛选器添加到其 Twig 环境中来从简化的双重策略中受益:
$twigEnv->addFunction(
new \Twig_SimpleFunction(
'form_token',
function($lock_to = null) {
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
if (empty($_SESSION['token2'])) {
$_SESSION['token2'] = random_bytes(32);
}
if (empty($lock_to)) {
return $_SESSION['token'];
}
return hash_hmac('sha256', $lock_to, $_SESSION['token2']);
}
)
);
使用此Twig函数,您可以使用两个通用令牌,如下所示:
<input type="hidden" name="token" value="{{ form_token() }}" />
或者锁定的变体:
<input type="hidden" name="token" value="{{ form_token('/my_form.php') }}" />
Twig只关注模板渲染;您仍然必须正确验证令牌。在我看来,Twig策略提供了更大的灵活性和简单性,同时保持了最大安全性的可能性。
一次性 CSRF 令牌
如果您有一个安全要求,即每个CSRF令牌只能使用一次,最简单的策略会在每次成功验证后重新生成它。但是,这样做会使每个以前的令牌失效,这些令牌与同时浏览多个选项卡的人不能很好地混合在一起。
Paragon Initiative Enterprises为这些角落案例维护了一个反CSRF库。它只适用于一次性每表单令牌。当会话数据中存储了足够的令牌(默认配置:65535)时,它将首先循环出最旧的未赎回令牌。