douxian1892 2014-05-22 23:51
浏览 83
已采纳

CSRF令牌不经时验证

I use Codeigniter/PHP. I use CSRF tokens (not the CI native version as I have my own form implementation) and from time to time the token is not validated.

The CSRF token is created once per session:

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;
}

It is passed to the form without issues in the csrfToken hidden input field, with htmlspecialchars applied to it (using urlencode makes no difference):

echo '<input type="hidden" name="'.$this->name.'" value="'.htmlspecialchars($this->value).'">';

This field has a validation rule 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;
    }
}

This is where things get weird. Sometimes $token is not correct and looks like corrupted data. Here are a couple of examples:

Error:

Value in $CI->session->userdata('csrfToken'): 6cT3O0KTOk7cVlear71lU7KKFlGONt4rS2HjNoSVFRM= (correct)

Value in $token: 6cT O0KTOk7cVlear71lU7KKFlG (4th character changed and missing end of string)

No error:

Value in $CI->session->userdata('csrfToken'): AiAgGqqxTxuCxN7h5HHRtcJjmHJVMRksBYbq6Dx4Kv4=

Value in $token: AiAgGqqxTxuCxN7h5HHRtcJjmHJVMRksBYbq6Dx4Kv4=

Any idea? I have checked and rechecked, the CRSF token is correctly set everywhere except in $token in my validation callback. And it only happens for certain tokens...

EDIT: so it seems that the base64 encoding was causing the issue (why, I don't know). I have replaced

$csrfHash = base64_encode(hash('sha256', uniqid(serialize($_SERVER), true), true));

by

$csrfHash = random_string('sha1');
  • 写回答

2条回答 默认 最新

  • dqg17080 2014-05-23 00:03
    关注

    This is just a wild guess, but could it be the combination of the Base64 encoding and submitting the form via HTTP POST, like described here:

    POST Base64 encoded data in PHP

    The solution could then be to urlencode() the token before posting?

    EDIT: The solution turns out to be dropping the base64 encoding of the token in favor of a plain sha256-hash as a token. See comments below.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥15 latex怎么处理论文引理引用参考文献