1

CodeIgniter / CSRF / JSON で問題が発生しました。

Content-Type "application/json" を使用して、HTTP POST リクエストを PHP バックエンドに送信しています。ペイロードは JSON データです。データとともに、生成され、CSRF Coo​​kie に保存された CSRF トークンを渡します。標準の POST を使用してFORM リクエストでは問題なく動作しますが、JSON として送信すると失敗します。

JSON コンテンツ タイプのために $_POST 配列が空であるため、CodeIgniter は Cookie の検証に失敗し、エラーをスローします。

CodeIgniter で JSON ペイロードをチェックし、CSRF トークンを検証するにはどうすればよいですか?

4

4 に答える 4

2

この問題を修正するには、「system/core/」にある「Security.php」ファイルのコードを変更する必要がありました。

関数「csrf_verify」で、そのコードを置き換えます。

// Do the tokens exist in both the _POST and _COOKIE arrays?
if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name]))
{
$this->csrf_show_error();
}
// Do the tokens match?
if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name])
{
$this->csrf_show_error();
}

そのコードで:

// Do the tokens exist in both the _POST and _COOKIE arrays?
if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])) {
    // No token found in $_POST - checking JSON data
    $input_data = json_decode(trim(file_get_contents('php://input')), true); 
    if ((!$input_data || !isset($input_data[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])))
        $this->csrf_show_error(); // Nothing found
    else {
        // Do the tokens match?
        if ($input_data[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name])
            $this->csrf_show_error();
    }
}
else {
    // Do the tokens match?
    if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name])
        $this->csrf_show_error();
}

このコードは最初に $_POST をチェックし、何も見つからない場合は JSON ペイロードをチェックします。

これを行う理想的な方法は、着信要求の Content-Type ヘッダー値を確認することです。しかし、驚くべきことに、それは簡単なことではありません...

誰かがより良い解決策を持っている場合は、ここに投稿してください。

乾杯

于 2013-09-14T06:10:42.067 に答える
0

As Brian write, you have to put your custom class into /application/core/ ex. My_Security.php

This is mine solution, work for me, i check the application/json content_type and request cookies.

defined('BASEPATH') OR exit('No direct script access allowed');

class MY_Security extends  CI_Security {


    public function csrf_verify()
    {

        // If it's not a POST request we will set the CSRF cookie
        if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
        {
            return $this->csrf_set_cookie();
        }

                /**
                 *  mine implementation for application/json
                 */
                $reqHeaders = getallheaders();
                $content_type = $reqHeaders["Content-Type"];

                #it's a json request?
                if(preg_match("/(application\/json)/i",$content_type))
                {
                    #the check the cookie from request
                    $reqCookies = explode("; ",$reqHeaders["Cookie"]);
                    foreach($reqCookies as $c)
                    {
                        if(preg_match("/(".$this->_csrf_cookie_name."\=)/", $c))
                        {
                          $c = explode("=",$c);

                          if($_COOKIE[$this->_csrf_cookie_name] == $c[1])
                          {
                             return $this; 
                          }
                        }
                    }

                }
                //< end

        // Check if URI has been whitelisted from CSRF checks
        if ($exclude_uris = config_item('csrf_exclude_uris'))
        {
            $uri = load_class('URI', 'core');
            foreach ($exclude_uris as $excluded)
            {
                if (preg_match('#^'.$excluded.'$#i'.(UTF8_ENABLED ? 'u' : ''), $uri->uri_string()))
                {
                    return $this;
                }
            }
        }

        // Do the tokens exist in both the _POST and _COOKIE arrays?
        if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])
            OR $_POST[$this->_csrf_token_name] !== $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
        {
            $this->csrf_show_error();
        }

        // We kill this since we're done and we don't want to polute the _POST array
        unset($_POST[$this->_csrf_token_name]);

        // Regenerate on every submission?
        if (config_item('csrf_regenerate'))
        {
            // Nothing should last forever
            unset($_COOKIE[$this->_csrf_cookie_name]);
            $this->_csrf_hash = NULL;
        }

        $this->_csrf_set_hash();
        $this->csrf_set_cookie();

        log_message('info', 'CSRF token verified');
        return $this;
    }

}
于 2015-12-03T00:28:26.263 に答える