Symfony 1.4:表单中CSRF的自定义错误消息

时间:2010-04-05 12:40:27

标签: forms symfony1 csrf sfguard

任何人都可以告诉我在Symfony 1.4中为表单定制CSRF令牌错误消息的位置/方式。我正在使用sfDoctrineGuard进行登录,特别是在会话用完且你仍然打开页面时,它会抛出一个非常用户不友好的错误:“检测到CSRF攻击”。类似“此会话已过期。请返回主页再试一次”听起来更好。

在表单类中执行此操作的正确方法是什么?

感谢。

6 个答案:

答案 0 :(得分:5)

唯一的方法似乎是覆盖sfForm::addCSRFProtection()

/lib/form/BaseForm.class.php中,您可以添加以下代码:

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.');
        }
    }
}

调用父方法后,检索与CSRF字段关联的验证器,并更改代码csrf_attack的消息。

编辑:您还需要检查验证程序是否存在。某些表单可能会禁用其CSRF保护!

希望这有帮助!

答案 1 :(得分:3)

这些答案都没有解释如何删除以非hackish方式为错误消息添加前缀的“CSRF令牌:”标签(例如,更改令牌名称是一个坏主意!)。

删除标签的唯一合理方法是扩展CSRF验证程序以引发全局错误。当我们这样做时,我们也可以更改错误消息。

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));
    }
  }
}

现在,让我们通过覆盖sfForm::addCSRFProtection中的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')
    ));
  }
}

答案 2 :(得分:2)

在1.4.4中,我不得不修改naag的代码......

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.');
  }
}

这使它工作,但是'csrf token:'位仍会显示在错误消息中。

答案 3 :(得分:2)

改进以前的答案,这是我使用的代码:

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");
    }
  }

NamedErrorRowFormatInARow的默认值是"<li>%name%: %error%</li>\n"添加名称和冒号。 要小心,因为它会更改所有表单和所有全局错误的值。

您还可以通过创建自定义表单格式化程序并在所需的表单中使用它来更改字段。您可以查看the documentation here了解更多相关信息。

答案 4 :(得分:1)

使用事件调度程序。看看http://bluehorn.co.nz/2010/07/15/how-to-change-csrf-attack-message-in-symfony-1-2/

我是为Symfony 1.2编写的,但是使用事件调度程序,所以它仍然适用于Symfony 1.4。

答案 5 :(得分:1)

我认为可以通过设置CSRF令牌字段的标签来删除或自定义“csrf token:”前缀,当然是全局。