Symfony 1.4: Custom error message for CSRF in forms
Asked Answered
A

6

7

Can anyone tell me where/how to customise the CSRF token error message for forms in Symfony 1.4. I'm using sfDoctrineGuard for logins and in this form particularly, whenever a session runs out and you still have the page open, it throws a very user-unfriendly error: "CSRF attack detected". Something like "This session has expired. Please return to the home page and try again" sounds better.

What's the right way to do this in the form class?

Thanks.

Amortization answered 5/4, 2010 at 12:40 Comment(0)
O
5

The only way seems to be to overwrite sfForm::addCSRFProtection().

In /lib/form/BaseForm.class.php you can add this piece of code:

class BaseForm extends sfFormSymfony
{
    public function addCSRFProtection($secret = null)
    {
        parent::addCSRFProtection($secret);
        if (array_key_exists(self::$CSRFFieldName, $this->getValidatorSchema())) {
            $this->getValidator(self::$CSRFFieldName)->setMessage('csrf_attack', 'This session has expired. Please return to the home page and try again.');
        }
    }
}

After calling the parent method, you retrieve the validator associated with the CSRF field and change the message for the code csrf_attack.

Edit: You also need to check whether or not the validator exists. Some forms might have their CSRF protection disabled!

Hope this helps!

Oligopsony answered 6/4, 2010 at 11:35 Comment(2)
@naag: thanks very much. Tried a few things but not that, will have a play. Seems like a minor oversight from the symfony guys.Amortization
I edited my answer to include a check for the existence of the CSRF validator :-)Oligopsony
H
3

None of these answers explain how to remove the "CSRF token:" label that prefixes the error message in a non-hackish way (e.g. changing the token name is a bad idea!).

The only sound way of removing the label is to extend the CSRF validator to throw a global error. While we do this, we can also change the error message.

class myValidatorCSRFToken extends sfValidatorCSRFToken
{
  protected function configure($options = array(), $messages = array())
  {
    parent::configure($options, $messages);
    $this->addMessage('csrf_attack', 'Your session has expired. Please return to the home page and try again.');
  }

  protected function doClean($value)
  {
    try {
      return parent::doClean($value);
    } catch (sfValidatorError $e) {
      throw new sfValidatorErrorSchema($this, array($e));
    }
  }
}

Now, let's set our forms to use this validator by overriding sfForm::addCSRFProtection in BaseForm:

public function addCSRFProtection($secret = null)
{
  parent::addCSRFProtection($secret);
  if (isset($this->validatorSchema[self::$CSRFFieldName])) //addCSRFProtection doesn't always add a validator
  {
    $this->validatorSchema[self::$CSRFFieldName] = new myValidatorCSRFToken(array(
        'token' => $this->validatorSchema[self::$CSRFFieldName]->getOption('token')
    ));
  }
}
Herod answered 22/4, 2011 at 18:39 Comment(0)
T
2

In 1.4.4 I had to modify naag's code like so...

public function addCSRFProtection($secret = null)
{
  parent::addCSRFProtection($secret);
  if (isset($this->validatorSchema[self::$CSRFFieldName])) {
    $this->validatorSchema[self::$CSRFFieldName]->setMessage('csrf_attack', 'This session has expired. Please refresh and try again.');
  }
}

This got it working, the 'csrf token:' bit still appears in the error message though.

Terwilliger answered 21/5, 2010 at 11:12 Comment(0)
W
2

Improving on previous answers, here is the code I use:

public function addCSRFProtection($secret = null)
  {
    parent::addCSRFProtection($secret);
    if (isset($this->validatorSchema[self::$CSRFFieldName])) {
      $this->validatorSchema[self::$CSRFFieldName]->setMessage('csrf_attack', 'This session has expired. Please refresh and try again.');
      $this->getWidgetSchema()->getFormFormatter()->setNamedErrorRowFormatInARow("    <li>%error%</li>\n");
    }
  }

The default value for the NamedErrorRowFormatInARow is "<li>%name%: %error%</li>\n" adding the name and the colon. Be careful because it changes the value for all forms and all global errors.

You can also change the field by creating a custom form formatter and using it in the forms you want. You can go look at the documentation here for more info on this.

Withhold answered 28/9, 2012 at 19:58 Comment(0)
C
1

Use event dispatcher. Check this out http://bluehorn.co.nz/2010/07/15/how-to-change-csrf-attack-message-in-symfony-1-2/

I wrote it for Symfony 1.2, but using event dispatcher, so it still might work for Symfony 1.4.

Cutaway answered 14/7, 2010 at 23:53 Comment(0)
R
1

I suppose the "csrf token:" prefix can be removed or customized by setting the label of the CSRF token field, globally of course.

Retire answered 19/1, 2011 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.