codeigniter csrf with ajax not working in IE codeigniter csrf with ajax not working in IE codeigniter codeigniter

codeigniter csrf with ajax not working in IE


As I suggest in my article. It is better to use the post in net.tutsplus with title: Protect a CodeIgniter Application Against CSRF . This is an old post and the solution is for Codeignter 1.7.x . However this is the only proper solution for Codeigniter 2 that I could find so far in order to achieve the CSRF protection in Codeigniter. The main issue that we have here is that Codeigniter uses the COOKIE . This post however uses the Codeigniter session that it is more safe to use and it is working for all the browsers without any issue. The article from net.tutsplus will work for AJAX and non AJAX request.

So my suggestion is that if you don't find a work around for your question, you can try to implement the article: Protect a CodeIgniter Application Against CSRF


Thanks to @John with the suggestion to implement CSRF by myself, I passed the first Issue. However, it turned out that IE is not submitting the post data at all (after debugging) So, there is a question on stackoverflow with the title IE is refusing to send data through $.ajaxand to solve this problem you have to add this meta tag to tell IE to work with javascript in IE9 compatibility mode.

<meta http-equiv="x-ua-compatible" content="IE=9" >

Now, for the article about using hooks to work around csrf, it misses one issue which is, if you are using .serializeArray() or any equivalent in jquery to submit your form, you need to modify the
validate_tokens function to check for the token_name inside the posted array.

Hope this will save someone having the same problem

Note: adding the meta tag without rewriting the csrf will not solve the problem.

Update 1:

Here's the Implementation I'm using:

<?php/** * Description of csrf_protection * @author Ian Murray */class Csrf_Protection {    private $CI;    private static $token_name = 'somename';    private static $token;    public function __construct() {        $this->CI = &get_instance();    }/**  * Generates a CSRF token and stores it on session. Only one token per session is generated.  * This must be tied to a post-controller hook, and before the hook  * that calls the inject_tokens method().  *  * @return void  * @author Ian Murray  */     public function generate_token()      {            // Load session library if not loaded            $this->CI->load->library('session');            if ($this->CI->session->userdata(self::$token_name) === FALSE)            {              // Generate a token and store it on session, since old one appears to have expired.              self::$token = md5(uniqid() . microtime() . rand());            $this->CI->session->set_userdata(self::$token_name, self::$token);            }            else            {              // Set it to local variable for easy access              self::$token = $this->CI->session->userdata(self::$token_name);            }      }      /**     * Validates a submitted token when POST request is made.     *     * @return void     * @author Ian Murray     */     public function validate_tokens()     {       // Is this a post request?       if ($_SERVER['REQUEST_METHOD'] == 'POST')       {         // Is the token field set and valid?         $posted_token = $this->CI->input->post(self::$token_name);         if($posted_token === FALSE){           $posted_token = $this->_get_token_in_post_array($this->CI->input->post());           $this->_check_all_post_array($posted_token);       }     }     }   /**   *takes the posted token and check it after multidimesional-array search   *@params $posted_token   *@author Mamdouh Alramadan   */   private function _check_all_post_array($posted_token)   {       if ($posted_token === 'error' || $posted_token != $this->CI->session->userdata(self::$token_name))         {           // Invalid request, send error 400.         show_error('Request was invalid. Tokens did not match.', 400);         }     }   /**     * This injects hidden tags on all POST forms with the csrf token.     * Also injects meta headers in <head> of output (if exists) for easy access     * from JS frameworks.     *     * @return void     * @author Ian Murray     */     public function inject_tokens()     {       $output = $this->CI->output->get_output();       // Inject into form       $output = preg_replace('/(<(form|FORM)[^>]*(method|METHOD)="(post|POST)"[^>]*>)/',                              '$0<input type="hidden" name="' . self::$token_name . '" value="' . self::$token . '">',                               $output);       // Inject into <head>       $output = preg_replace('/(<\/head>)/',                              '<meta name="cname" content="' . self::$token_name . '">' . "\n" . '<meta name="cval" content="' . self::$token . '">' . "\n" . '$0',                               $output);       $this->CI->output->_display($output);     }  /** * takes the posted array and check for the token inside it  * @params $arr array * @author Mamdouh Alramadan */   private function _get_token_in_post_array($arr)   {//this function is customized to my case but it's easy to adapt       if(is_array($arr)){        $key = $this->_recursive_post_array_search(self::$token_name, $arr);//this will return data if token found        if($key === 'data'){//I'm expecting the token inside data array            $key = $this->_recursive_post_array_search(self::$token_name, $arr['data']);            return isset($arr['data'][$key]['value'])?$arr['data'][$key]['value']:FALSE;        }       }       return 'error';   }   //some custom function to do multi-dimensional array search, can be replaced with any other searching function.   private function _recursive_post_array_search($needle,$haystack) {        foreach($haystack as $key=>$value) {            $current_key=$key;            if($needle===$value OR (is_array($value) && $this->_recursive_post_array_search($needle,$value) !== false)) {                return $current_key;            }        }        return false;    }}?>