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.

    已采纳该答案
    打赏 评论
  • dongtan3306 2014-05-23 03:27

    Please use the config for the CSRF.

    You can enable csrf protection by opening your application/config/config.php file and setting this:

    $config['csrf_protection'] = TRUE;

    // This will automatically generate the hidden field for form_open(params) function, so you no need to do it every time. This feature is included the frame work.

    To avoid CSRF to specific URIs http://ellislab.com/forums/viewthread/182631/

    打赏 评论

相关推荐 更多相似问题