我使用Codeigniter / PHP。我使用CSRF令牌(不是CI本机版本,因为我有自己的表单实现),并且有时不会验证令牌。
每个会话创建一次CSRF令牌:
function create_csrf_token() //If needed, creates a session variable; returns a hash to use for CSRF protection
{
$CI =& get_instance();
if($CI->session->userdata('csrfToken')) //the token already exists: use its hash
{
$csrfHash = $CI->session->userdata('csrfToken');
}
else //no token yet: create session variable + set its hash
{
$csrfHash = base64_encode(hash('sha256', uniqid(serialize($_SERVER), true), true));
$CI->session->set_userdata(array('csrfToken' => $csrfHash));
}
return $csrfHash;
}
它被传递给csrfToken隐藏输入字段中没有问题的表单,并且htmlspecialchars
被应用于它(使用urlencode
没有区别):
echo '<input type="hidden" name="'.$this->name.'" value="'.htmlspecialchars($this->value).'">';
此字段包含验证规则verify_csrf
:
public function verify_csrf($token)
{
$CI =& get_instance();
if($CI->session->userdata('csrfToken') && $CI->session->userdata('csrfToken') == $token) return true;
else
{
$this->set_message('verify_csrf', 'Invalid token');
return false;
}
}
这就是事情变得奇怪的地方。有时$token
不正确,看起来像是损坏的数据。以下是几个例子:
错误:
$CI->session->userdata('csrfToken')
中的值:6cT3O0KTOk7cVlear71lU7KKFlGONt4rS2HjNoSVFRM=
(正确)
$token
中的值:6cT O0KTOk7cVlear71lU7KKFlG
(第4个字符已更改且缺少字符串结尾)
没有错误:
$CI->session->userdata('csrfToken')
中的值:AiAgGqqxTxuCxN7h5HHRtcJjmHJVMRksBYbq6Dx4Kv4=
$token
中的值:AiAgGqqxTxuCxN7h5HHRtcJjmHJVMRksBYbq6Dx4Kv4=
有什么想法吗?我已经检查并重新检查,除了在我的验证回调中的$ token之外,CRSF令牌在任何地方都被正确设置。它只发生在某些令牌上......
编辑:所以似乎base64编码引起了问题(为什么,我不知道)。我已经取代了$csrfHash = base64_encode(hash('sha256', uniqid(serialize($_SERVER), true), true));
通过
$csrfHash = random_string('sha1');
答案 0 :(得分:1)
这只是一个疯狂的猜测,但可能是Base64编码和通过HTTP POST提交表单的组合,如下所述:
POST Base64 encoded data in PHP
然后解决方案可能是在发布之前使用urlencode()令牌吗?
编辑:解决方案结果是丢弃了令牌的base64编码,转而使用普通的sha256-hash作为令牌。见下面的评论。
答案 1 :(得分:0)
请使用CSRF的配置。
您可以通过打开application / config / config.php文件并设置此项来启用csrf保护:
$config['csrf_protection'] = TRUE;
//这将自动生成form_open(params)
函数的隐藏字段,因此您无需每次都执行此操作。框架工作包含此功能。
避免将CSRF转换为特定的URI http://ellislab.com/forums/viewthread/182631/