Zend Form - 一页中的多个表单和(CSRF)令牌验证

Posted

技术标签:

【中文标题】Zend Form - 一页中的多个表单和(CSRF)令牌验证【英文标题】:Zend Form - multiple forms in one page and (CSRF) token validations 【发布时间】:2011-06-13 11:06:59 【问题描述】:

我使用 Zend-Form 在我的项目中生成表单。

第一:如何处理同一页面上的多个表单,并且只发布提交的表单?

第二:当我在同一页面上有两个表单时,令牌只会验证 html 中最顶层呈现的表单。第二个表单出现“令牌不匹配”错误,从而使表单无法发布。如何给每个表单一个不与其他表单冲突的唯一令牌?

真诚的,为什么

【问题讨论】:

***.com/questions/1170857/… 解决第一个。第二个问题呢? 你为每个表单渲染了一个csrf字段吗? 【参考方案1】:

当我在同一页面上有两个表单时,令牌只会验证 HTML 中最顶层呈现的表单。第二个表单出现“令牌不匹配”错误,从而使表单无法发布。如何给每个表单一个不与其他表单冲突的唯一令牌?

当前的implementation 无法使用多种形式的令牌(请参阅initCsrfValidator)。

我建议您生成自己的令牌,将其存储在会话中(使用表单 ID)并自行验证。

【讨论】:

我认为只要有不同的会话对象来存储它们的哈希值,您就可以使用哈希值来处理多个表单?由于会话命名空间使用对象名称,因此如果您给它们不同的名称,似乎会发生这种情况。【参考方案2】:

我在尝试使用Zend_Form_Element_Hash 在同一页面上创建两个表单时发现了这个问题。有两种方法可以实现,都是mentioned in the documentation:

哈希元素的名称应该是唯一的。我们建议对元素使用 salt 选项 - 具有相同名称和不同 salt 的两个哈希不会发生冲突

所以...

    为每个 Hash 元素使用唯一名称 为每个 Hash 元素使用唯一的盐值

【讨论】:

【参考方案3】:

我遇到了同样的情况

当我在同一页面上有两个表单时,令牌只会验证 HTML 中最顶层呈现的表单。第二种形式得到一个 “令牌不匹配”错误,从而使表单无法发布。如何 你是否给每个表格一个唯一的标记,它不与 其他人?

一种可能的解决方案是使用单独的表单仅用于令牌生成和验证。然后在 HTML 中,每个表单都有自己的标记元素,但具有相同的值。如果您提交一个表单,则使用您用于生成它的表单验证此令牌元素。如果您混合使用 ajax 表单和经典 POST 表单,那么您可以在响应中发送一个新令牌并将其分配给每个令牌元素。

//Finally set the response token
    $form->getElement('token')->render();   //Need to call render in order to regenerate the token
    $response['token'] = $form->getElement('token')->getValue();
    $this->_helper->json($response);

在 jquery 中你可以有类似 $('._token').val(response.token)

事实上,这比必须向每个表单添加 Zend_Form_Element_Hash 非常简单,甚至更好。

【讨论】:

【参考方案4】:

实际上,我刚刚修复了一个类似的问题,即我生成了具有 csrf 保护的相同表单的多个副本。发生的事情是只有最后一个创建的表单具有正确的 csrf 令牌。

处理这个问题的草率方法是更改​​ Zend 库中的跃点(在 Zend_Form_Element_Hash 文件中),以便令牌在 1 次刷新或页面加载后不会过期。这是解决问题的一种非常简单的方法,但只有在您知道页面将加载多少次时才有效。这是创可贴解决方案

执行此操作的正确方法是在页面加载后执行 ajax 调用以获取新的刷新令牌。然后使用您的 javascript 库(jquery 可能是最简单的)并找到令牌的所有实例并将它们全部替换为新的。

所以就代码而言,它看起来像这样: 控制器:

$form->hash->initCsrfToken();

$this->view->hash = $form->hash->getValue();

在您的 js 文件中(如果您使用的是 jquery)

$(.hash).replaceWith('HiddenHtmlPart1' . =hash . 'HiddenHtmlPart2'); 重要的部分是选择器选择所有隐藏的元素。然后你只需要替换隐藏元素的内部。相同的想法适用于其他 js 库,尽管它会涉及不同的方法。

【讨论】:

以上是关于Zend Form - 一页中的多个表单和(CSRF)令牌验证的主要内容,如果未能解决你的问题,请参考以下文章

如何使 react-hook-form 在一页中使用多个表单?

php 一页中有多个相同的表单

对 Zend_Form 中的特定子表单使用自定义 isValid() 函数

一页中的多个模式

引导表中的表多重排序不适用于一页中的多个表

一页中的多个 Summernote 所见即所得编辑器具有相同的占位符