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

时间:2011-06-13 11:06:59

标签: php zend-form

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

首先:如何在同一页面上处理多个表单,并仅发布提交的表单?

第二:当我在同一页面上有两个表单时,令牌将仅验证HTML中最顶层的呈现形式。第二种形式与“令牌不匹配”错误,从而使表单无法发布。如何为每个表单提供一个与其他表单不冲突的唯一标记?

真诚地,为什么

4 个答案:

答案 0 :(得分:6)

  

当我在同一页面上有两个表单时,令牌将仅验证HTML中最顶层的呈现表单。第二种形式与“令牌不匹配”错误,从而使表单无法发布。如何为每个表单提供一个与其他表单不冲突的唯一标记?

当前implementation无法使用多种表单上的代币(请参阅initCsrfValidator)。

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

答案 1 :(得分:3)

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

  

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

因此...

  1. 为每个Hash元素使用唯一名称
  2. 为每个Hash元素使用唯一的salt值

答案 2 :(得分:0)

我遇到了与

相同的情况
  

当我在同一页面上有两个表单时,令牌只会验证   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简单甚至更好。

答案 3 :(得分:0)

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

处理此问题的方法是更改​​Zend库中的跳(在Zend_Form_Element_Hash文件中),以便在刷新或页加载后令牌不会过期。这是解决问题的一种非常简单的方法,但只有在您知道页面加载次数时才有效。这是绑定解决方案

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

所以在代码方面,它看起来像这样: 控制器:

  

$形式 - >散列> initCsrfToken();

     

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

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

  

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