Search code examples
phpzend-framework2csrfcsrf-protectionzend-validate

zf2 csrf not working


We can easily break CSRF of ZF2. If we remove the string after the hyphen(-) the CsrfValidator does not give any error and the token is successfully submitted.

For example CSRF token = 245454547kck-kjhjh2454dh after editing the token token = 245454547kck- ZF2 successfully submits the form, but it must give an error.

Can anyone check this and let me know if there is a solution for this issue.

For above scenario we use:

$csrfValidator = new CsrfValidator(array(
    'name'=> 'token_name',//(here i used 'csrf' also)
    'salt'=> 'test_salt',
));
$csrf = new CsrfElement('token_name');
$csrf->setCsrfValidator($csrfValidator);
$this->add($csrf);
$this->csrf = $csrf;

validator :

$inputFilter->add(
    $factory->createInput(array(
        'name'     => 'token_name',
        'required' => true,
        'validators' => array(
            $this->csrf->getCsrfValidator()
        )
    ))
);

Please provide a solution.


Solution

  • As far as I can tell from the code, this is expected behavior in order to maintain backwards compatibility.

    The second part of the string is a token ID (not an actual anti-CSRF token) used to keep track of multiple anti-CSRF tokens in the same session. If no ID is set during validation (like in your example) the code merely checks for the hash in the session store. The source code indicates that this was put in avoid a BC break (see source code)

    If you really wanted to enforce the token ID, you could extend Zend\Validator\Csrf and override getValidationToken() (i.e. removing the BC code):

    class MyCustomCsrf extends \Zend\Validator\Csrf
    {
        /**
         * Get validation token
         *
         * Retrieve token from session, if it exists.
         *
         * @override
         * @param string $tokenId
         * @return null|string
         */
        protected function getValidationToken($tokenId = null)
        {
            $session = $this->getSession();
            if ($tokenId && isset($session->tokenList[$tokenId])) {
                return $this->formatHash($session->tokenList[$tokenId], $tokenId);
            }
            return;
        }
    }