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

Posted

技术标签:

【中文标题】Symfony 1.4:表单中 CSRF 的自定义错误消息【英文标题】:Symfony 1.4: Custom error message for CSRF in forms 【发布时间】:2011-02-04 10:10:33 【问题描述】:

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

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

谢谢。

【问题讨论】:

【参考方案1】:

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

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 的默认值为"&lt;li&gt;%name%: %error%&lt;/li&gt;\n",加上名称和冒号。 请小心,因为它会更改所有表单和所有全局错误的值。

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

【讨论】:

【参考方案2】:

这些答案都没有解释如何以非骇客的方式删除错误消息前缀的“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));
    
  

现在,让我们通过在BaseForm 中覆盖sfForm::addCSRFProtection 来设置我们的表单以使用此验证器:

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

【讨论】:

【参考方案3】:

在 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:”位仍然出现在错误消息中。

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

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

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

【讨论】:

【参考方案6】:

似乎唯一的方法是覆盖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 保护!

希望这会有所帮助!

【讨论】:

@naag:非常感谢。尝试了一些东西,但不是那样,会玩。似乎是 symfony 的一个小疏忽。 我编辑了我的答案,包括检查 CSRF 验证器是否存在 :-)

以上是关于Symfony 1.4:表单中 CSRF 的自定义错误消息的主要内容,如果未能解决你的问题,请参考以下文章

CSRF 令牌无效。请尝试重新提交表单。 Symfony 4

Symfony 4 - 如何在不构建表单的情况下添加 csrf 令牌?

将自定义参数传递给 Symfony2 中的自定义 ValidationConstraint

Symfony 2 在使用没有类的表单时添加 CSRF 令牌

VueJs 前端的无效 CSRF 令牌错误(symfony 5)

Symfony 5 登录表单操作返回无效的 CSRF 令牌