【问题标题】:CSRF token not validated from times to timesCSRF 令牌不时验证
【发布时间】:2014-07-12 04:53:33
【问题描述】:

我使用 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-&gt;session-&gt;userdata('csrfToken') 中的值:6cT3O0KTOk7cVlear71lU7KKFlGONt4rS2HjNoSVFRM=(正确)

$token 中的值:6cT O0KTOk7cVlear71lU7KKFlG(第 4 个字符已更改且缺少字符串结尾)

没有错误

$CI-&gt;session-&gt;userdata('csrfToken') 中的值:AiAgGqqxTxuCxN7h5HHRtcJjmHJVMRksBYbq6Dx4Kv4=

$token 中的值:AiAgGqqxTxuCxN7h5HHRtcJjmHJVMRksBYbq6Dx4Kv4=

有什么想法吗?我已经检查并重新检查,CRSF 令牌在任何地方都正确设置,除了在我的验证回调中的 $token 中。而且它只发生在某些令牌上......

编辑:所以似乎是 base64 编码导致了这个问题(为什么,我不知道)。我换了

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

通过

$csrfHash = random_string('sha1');

【问题讨论】:

    标签: php forms codeigniter csrf


    【解决方案1】:

    这只是一个疯狂的猜测,但它可能是 Base64 编码和通过 HTTP POST 提交表单的组合,如下所述:

    POST Base64 encoded data in PHP

    然后解决方案可能是在发布之前对令牌进行 urlencode()?

    编辑: 解决方案是放弃标记的 base64 编码,转而使用普通的 sha256-hash 作为标记。请参阅下面的 cmets。

    【讨论】:

    • 感谢您的评论!不幸的是,这没有什么区别(我忘了提到在为 csrfToken 字段生成 html 时我已经在使用 htmlspecialchars - 用 urlencode 替换它仍然显示相同的问题)
    • 可能是与表单的 Content-Type 或 enctype-attribute 相关的东西(即“multipart/form-data”)吗?
    • 典型形式:
      在 html 头中带有
    • 我想知道是否有特殊原因对令牌进行 base64 编码,而不仅仅是将 sha256 哈希作为令牌传递? (只是为了验证问题与base64编码数据无关)
    • 是的,我也这么认为,并用 $csrfHash = random_string('sha1'); (使用本机 CI 字符串助手)现在似乎可以工作了!如果您编辑初始解决方案以提及该解决方案,我会将其标记为已接受。非常感谢您的帮助!!
    【解决方案2】:

    请使用 CSRF 的配置。

    您可以通过打开您的 application/config/config.php 文件并设置以下内容来启用 csrf 保护:

    $config['csrf_protection'] = TRUE;

    //这会自动为form_open(params)函数生成隐藏字段,所以你不需要每次都这样做。此功能包含在框架中。

    为了避免 CSRF 到特定的 URI http://ellislab.com/forums/viewthread/182631/

    【讨论】:

    • 如前所述,该站点使用了更复杂的表单系统,通常不使用 form_open。改变这一点基本上需要重构一切。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 2017-12-14
    • 2018-05-10
    • 2019-03-22
    • 2018-02-01
    • 1970-01-01
    • 2021-08-30
    相关资源
    最近更新 更多