Welcome Guest, Not a member yet? Register   Sign In
Security class in CI 2
#1

[eluser]musonic[/eluser]
I'm having a few problems with the CSRF implementation in CI 2. When a user submits a form with no errors everything works fine. However, if the form is submitted with errors then the form view is reloaded with the form errors shown. If the user then resubmits the form the CSRF token does not match the cookie and so the submission fails.
Can anyone help? Thanks.
#2

[eluser]Twisted1919[/eluser]
the problem lies in the csrf_verify method :
Code:
function csrf_verify()
    {
        // If no POST data exists we will set the CSRF cookie
        if (count($_POST) == 0)
        {
            return $this->csrf_set_cookie();
        }

        // Do the tokens exist in both the _POST and _COOKIE arrays?
        if ( ! isset($_POST[$this->csrf_token_name]) OR ! isset($_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();
        }
// THE PROBLEM STARTS FROM HERE

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

        log_message('debug', "CSRF token verified ");
    }
The method assumes that after the post data has been added everything is fine, which is wrong because allows you to try only once with a token, then if you resubmit the form, the cookie token is renewed but not the one from the post(actually in post there's nothing after this step, because they unset it) .
So this can be considered a bug, because it is not logic to work this way, and without extending the Security class to overwrite this method , is useless .

So, a re-writed method would look like so :
Code:
function csrf_verify()
    {
        // If no POST data exists we will set the CSRF cookie
        if (count($_POST) == 0)
        {
            return $this->csrf_set_cookie();
        }

        // Do the tokens exist in both the _POST and _COOKIE arrays?
        if ( ! isset($_POST[$this->csrf_token_name]) OR ! isset($_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();
        }
// We kill this since we're done and we don't want to polute the _POST array

//No we don't kill it, because we really want it to work.        
//unset($_POST[$this->csrf_token_name]);
        
        
        //unset($_COOKIE[$this->csrf_cookie_name]);
        //$this->_csrf_set_hash();// not such a good ideea.
        //$this->csrf_set_cookie();// if we set the cookie again, won't match what we have in post.

        log_message('debug', "CSRF token verified ");
    }
I think the above will work (not tested) but having in mind that the cookie is renewed when there's no post data and the csrf_hash is generated when the class is initialized, should work .
#3

[eluser]WanWizard[/eluser]
There are a lot of shortcomings with the current CRSF implementation. Try to open your site in two windows, both with a form. Or a page that has two forms... There is definately room for improvement.

For ExiteCMS, I store the tokens in the session, and I store them in an array, so I can have multiple tokens active at any given time. I also keep used tokens for a while, which allows me to capture reloads of a posted form, or people using the back button and then submitting the form again.




Theme © iAndrew 2016 - Forum software by © MyBB