对于安全代码,请不要以这种方式生成令牌: $token = md5(uniqid(rand(), TRUE));
试试看:
生成CSRF令牌
PHP 7
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];
旁注:我老板的一个开源项目是一项向后移植random_bytes()
并random_int()
进入PHP 5项目的计划。它是MIT许可的软件,可在Github和Composer上以paragonie / random_compat的形式获得。
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+,但对于具有hash-compat库的早期版本可用)。
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...
}
在不知道的情况下,无法为另一种形式重用为一种形式生成的令牌$_SESSION['second_token']
。重要的是,使用一个单独的令牌作为HMAC密钥,而不是您刚刚在页面上拖放的令牌。
奖励:混合方法+ Twig集成
使用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)时,它将首先循环出最旧的未兑换令牌。
token_time
用?