CSRF令牌不经时验证

时间:2014-05-22 23:51:02

标签: php forms codeigniter csrf

我使用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');

2 个答案:

答案 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/