We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

CSRF Ajax Refresh Token & set session

OK so I'm trying to be a bit clever, and in forms submitted via ajax, rather than give user a CSRF error if they have not submitted before the token expires, and force them to refresh the page and clear the form, I want to regenerate the CSRF token from within the controller, send it back to the form via the ajax callback. This updates the hidden CSRF field in the form, but as there is no page refresh, the token isn't refreshed in the session.

How can I update the CSRF token in the session manually via the controller?



20.4k

I have tried this $this->session->set($this->security->getTokenKey(), $this->security->getToken()); but it doesn't work.



20.4k

Thanks, that is interesting and may well come in handy, but it's not quite what I'm after. I'm now having problems trying to get CSRF working at all in 2.0.9 with my ajax form. I was sure it worked earlier although I hadn't fully tested it then.

That kind of takes me back to my original question on how to manually set the CSRF session. I would like to know more about how the CSRF system actually works. The reason CSRF is failing on my form at the moment seems to be because the CSRF session is not getting set, but the key and token are being generated in the form. If I call getSessionToken () and display it in my error output, nothing is displayed. I have CSRF working in non ajax forms, and sessions are enabled and working.



85.5k

for me , in 2.1.x csrf doesn't work at all

https://github.com/phalcon/cphalcon/issues/11009

hopefully someone else can help you



20.4k

In the end I have made my own CSRF system which turned out to be quite quick and easy and it doesn't suffer from the issues of the built in one. Mine uses a single cookie with a default expirey which can be overridden when called in a form. {{ csrfField() }} sets the hidden field and the cookie. The cookie is valid for all forms on the site, so if someone has multiple forms open in multiple tabs, they wont have issues. For ajax form submission, it is also possible to set a new cookie and return a new csrf field with the error in the form. So the user can just resubmit with out refreshing and loosing their content.

/**
 * Generate the CSRF stamp (name) and token in the cookie & field
 */
public static function csrfField($expire = 60) {
    $csrf = \Phalcon\DI::getDefault()->getShared('cookies')->get('csrf');
    $exp = explode('|', $csrf);
    if (ISSET($exp[0]) && ISSET($exp[1])) {
        $stamp = $exp[0];
        $hash = $exp[1];
        return '<input type="hidden" name="' . $stamp . '" value="' . $hash . '">';
    } else {
        $seed = mt_rand(1000, mt_getrandmax());
        $hash = md5($seed);
        $stamp = time();
        \Phalcon\DI::getDefault()->getShared('cookies')->set('csrf', $stamp . '|' . $hash, time() + ($expire * 60));
        if(\Phalcon\DI::getDefault()->getShared('cookies')->get('csrf')) {
            return '<input type="hidden" name="' . $stamp . '" value="' . $hash . '">';
        }
    }
}

/**
 * Check the CSRF tocken
 * @return bool
 */
public static function csrfCheck() {
    $csrf = \Phalcon\DI::getDefault()->getShared('cookies')->get('csrf');
    $exp = explode('|', $csrf);
        if (ISSET($exp[0]) && ISSET($exp[1])) {
            $stamp = $exp[0];
            $token = $exp[1];
            $str = \Phalcon\DI::getDefault()->getShared('request')->getPost("$stamp");
            if ($str === $token) {
                return TRUE;
            }
        }
    return FALSE;
}