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 validation does not work on remote server

Hello,

I have some forms on my site that also have csrf validation attached with the standard $this->security->getTokenKey() and $this->getToken()

In my controller I check the token as usual:

$this->security->checkToken()

THe problem is though that the CSRF validation works perfectly on my local machine (running XAMPP) but doesn't on my remove server (CentOS with Apache/PHP/MariaDB).

I'm running on PHP5.5 and using PhalconPHP version 1.3.4.

What could it be caused by?



58.4k

HI

This error can occur when the folder session PHP haven't permissons , refer to it https://github.com/puphpet/puphpet/issues/274

edited Feb '15

Hi,

Sorry on the late reply. I checked my php.ini to find out what my session.save_path is and it wasn't set (PHP\s default is nothing). So i set it to /var/lib/php/session based on the issue from Github and then chowned it to root:apache. This however doesn't seem to have been the issue as for some reason the validation still fails.

After searching through the forum earlier, I did notice that some people noted a wierd csrf behaviour with the absence of a favicon.ico. In my local server, my application picks up xampp\s favicon from the htdocs directory whereas my remote server doesn't have any favicon. Could this be the same case here?

I did try adding this to my project_root/.htaccess and my project_root/public/.htaccess:

RedirectMatch 204 /robots.txt
RedirectMatch 204 /favicon.ico

But it doesn't seem to have worked. DId I add this correctly? Or could it be caused by something else still?

Updated: It does seem to be a session issue no doubt. I tested by doing

var_dump($this->security->getSessionToken());

And it returned NULL. Doing session_save_path() returns me /var/lib/php/session as I've set it previously. I also checked if it is_writable and it returned me true.

Updated #2: I set the session.save_path to /tmp and now getSessionToken() is no longer NULL however the CSRF validation still fails.



2.1k
Accepted
answer
edited Feb '15

currently there are some issues when you get double calls, i know chrome had that issue, one good workaround is to use a session one time csrf key, basically it will always be the same key during the session unless you explictly change it.

class Security extends \Phalcon\Security
{
    public function getTokenKey($numberBytes = 13)
    {
        $key = '$PHALCON/CSRF/KEY$';

        $tokenKey = \Phalcon\DI::getDefault()->get('session')->get($key);

        if ($tokenKey)
        {
            return $tokenKey;
        }

        return parent::getTokenKey($numberBytes);
    }   

    public function getToken($numberBytes = 32)
    {
        $key = '$PHALCON/CSRF$';

        $token = \Phalcon\DI::getDefault()->get('session')->get($key);

        if ($token)
        {
            return $token;
        }

        return parent::getToken($numberBytes);
    } 

    public function changeToken($numberBytes = 32)
    {
        return parent::getToken($numberBytes);
    }

}

You can set the session to any directory, if you are on shared hosting, best to put it in a local folder instead of the default.

// You may have a better location, I plan to put this on my shared hosting account
$di->setShared('session', function() {
            session_save_path(__DIR__ . '/../apps/data/sessions/');
            $session = new Phalcon\Session\Adapter\Files([
                'uniqueId' => 'eh_',
            ]);
            $session->start();
            return $session;
        });

A huge thanks. your solution did the trick :). I don't know why the default way doesn't work on my remote server but I'm happy that this finally resolved it.