CodeIgniter CSRF token in JSON request CodeIgniter CSRF token in JSON request codeigniter codeigniter

CodeIgniter CSRF token in JSON request


Alternatively, you can skip the CSRF checking by adding following code on application/config/config.php below Line No. 351 (based on CI 2.1.4).

 $config['csrf_expire'] = 7200; // This is line no. 351/* If the REQUEST_URI has method is POST and requesting the API url,    then skip CSRF check, otherwise don't do. */if (isset($_SERVER["REQUEST_URI"]) &&   (isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'POST') )){    if (stripos($_SERVER["REQUEST_URI"],'/api/') === false )  { // Verify if POST Request is not for API        $config['csrf_protection'] = TRUE;    }    else {        $config['csrf_protection'] = FALSE;    }} else {    $config['csrf_protection'] = TRUE;}


To fix that issue, I had to change the code of the "Security.php" file located in "system/core/".

In function "csrf_verify", replace that code:

// 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();}

By that code:

// 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();}

That code first checks $_POST then if nothing has been found, it checks the JSON payload.

The ideal way of doing this would be to check the incoming request Content-Type header value. But surprisingly, it's not straight forward to do ...

If someone has a better solution, please post it here.

Cheers


If this needs to be overridden, best to extend the Security library rather than editing the core file directly.

Create the file My_Security.php in application/core/ and add the following (from the solution above):

<?phpclass My_Security extends CI_Security {    /**     * Verify Cross Site Request Forgery Protection     *     * @return  object     */    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();        }        // 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();        }        // We kill this since we're done and we don't want to        // polute the _POST array        unset($_POST[$this->_csrf_token_name]);        // Nothing should last forever        unset($_COOKIE[$this->_csrf_cookie_name]);        $this->_csrf_set_hash();        $this->csrf_set_cookie();        log_message('debug', 'CSRF token verified');        return $this;    }}