7

谁能告诉我在哪里/如何为 Symfony 1.4 中的表单自定义 CSRF 令牌错误消息。我正在使用 sfDoctrineGuard 进行登录,特别是在这种形式下,每当会话用完并且您仍然打开页面时,它会引发一个非常用户不友好的错误:“检测到 CSRF 攻击”。类似“此会话已过期。请返回主页并重试”之类的内容听起来更好。

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

谢谢。

4

6 回答 6

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 保护!

希望这可以帮助!

于 2010-04-06T11:35:11.957 回答
3

这些答案都没有解释如何以非骇客的方式删除错误消息前面的“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::addCSRFProtectionin来设置表单以使用此验证器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')
    ));
  }
}
于 2011-04-22T18:39:50.590 回答
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:' 位仍然出现在错误消息中。

于 2010-05-21T11:12:26.240 回答
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"添加名称和冒号。请小心,因为它会更改所有表单和所有全局错误的值。

您还可以通过创建自定义表单格式化程序并在您想要的表单中使用它来更改字段。您可以在此处查看文档以获取更多信息。

于 2012-09-28T19:58:48.627 回答
1

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

于 2011-01-19T15:11:28.443 回答
1

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

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

于 2010-07-14T23:53:42.203 回答