2013-09-14 18 views
1

У меня возникла проблема с CodeIgniter/CSRF/JSON.Значок CSRF CodeIgniter в запросе JSON

Я отправляю HTTP-запросы POST на мой PHP-сервер с помощью приложения/json Content-Type. Полезная нагрузка - это данные JSON. Наряду с данными я передаю токен CSRF, который сгенерирован и сохранен в файле cookie CSRF. С стандартным запросом POST FORM он работает нормально, но при отправке в качестве JSON он терпит неудачу. Поскольку массив $ _POST пуст из-за содержимого содержимого JSON, CodeIgniter не может проверить cookie и выдает ошибку.

Как я могу использовать CodeIgniter для проверки полезной нагрузки JSON и проверки моего токена CSRF?

ответ

1

Чтобы исправить это, ue, мне пришлось изменить код файла «Security.php», расположенный в «system/core /».

В функции "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. Но удивительно, что это не прямо ...

Если у кого-то есть лучшее решение, отправьте его здесь.

Приветствия

+0

Лучше всего это сделать, расширив библиотеку безопасности, вместо того, чтобы изменять основной файл непосредственно в системе/ядре. Создайте My_Security.php в приложении/ядре и переопределите csrf_verify(). Подробнее о том, как это сделать: https://ellislab.com/codeigniter/user-guide/general/core_classes.html –

2

В качестве альтернативы, можно пропустить CSRF проверки, добавив следующий код на приложение/Config/config.php ниже линии № 351 (на основе 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; 
} 
0

Если это необходимо переопределить, лучше всего расширить библиотеку безопасности, а не напрямую редактировать основной файл.

Создайте файл My_Security.php в приложении/ядра/и добавить следующее (из раствора выше):

<?php 
class 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; 
    } 

} 
0

Как Брайан записи, вы должны поместить свой собственный класс в/приложение/ядро ​​/ ех. My_Security.php

Это мое решение, работа для меня, я проверяю приложение/json content_type и запрашиваю файлы cookie.

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

} 
Смежные вопросы