表单提交后Zend Hash会话变量丢失

时间:2011-12-11 21:27:54

标签: php session zend-form zend-form-element zend-framework

我有一个包含3个表单的页面,每个表单都有一个用于CSRF保护的Zend_Form_Element_Hash。

问题在于其中2个与CSRF配合良好,但另一个在Hash中存在问题。

我第一次提交时,会返回“missingToken”错误。在那之后,如果我再次尝试提交它,它可以正常工作....

我创建了一个var_dump($ _ SESSION)来查看发生了什么,输出是:

在视图中(创建表单时):

array(7) {
...
    ["__ZF"]=>
    array(3) {
        ["Zend_Form_Element_Hash_routeSearch_csrf"]=>
        array(2) {
            ...
        }
        ["Zend_Form_Element_Hash_registration_csrf"]=>
        array(2) {
            ...
        }
        ["Zend_Form_Element_Hash_login_csrf"]=>
        array(2) {
            ...
        }
    }
    ["Zend_Form_Element_Hash_routeSearch_csrf"]=>
    array(1) {
        ["hash"]=>
        string(32) "2e348e982e5d8849a7bcb3f42fdd6c0d"
    }
    ["Zend_Form_Element_Hash_registration_csrf"]=>
    array(1) {
        ["hash"]=>
        string(32) "6fd74223bb158cc3cc780ee29b26ae58"
    }
    ["Zend_Form_Element_Hash_login_csrf"]=>
    array(1) {
        ["hash"]=>
        string(32) "d07dc1ac514082f1960c300670414399"
    }
}

提交后:

array(6) {
...
    ["__ZF"]=>
    array(2) {
        ["Zend_Form_Element_Hash_login_csrf"]=>
        array(2) {
            ...
        }
        ["Zend_Form_Element_Hash_routeSearch_csrf"]=>
        array(2) {
            ...
        }
    }
    ["Zend_Form_Element_Hash_login_csrf"]=>
    array(1) {
        ["hash"]=>
        string(32) "d07dc1ac514082f1960c300670414399"
    }
    ["Zend_Form_Element_Hash_routeSearch_csrf"]=>
    array(1) {
        ["hash"]=>
        string(32) "b9378bec2fd18cf232f451ed602acf0a"
    }
}

如您所见,“Zend_Form_Element_Hash_registration_csrf”已经消失......

我尝试了所有我知道的但没有找到什么可以让会话消失......有什么想法吗? Zend会导致什么原因?

顺便说一句,其中两个表单由不同的Action中的同一个Controller加载(其中一个是有问题的表单)。这可能是会议消失的原因吗?

请帮助,因为我不知道该怎么做才能找到问题......我被困在这里= S.

------编辑------

好的,我找到了导致这种情况的原因......问题是表单有Ajax请求,当它们发生时,CSRF Hash到期(Hop = 1)。

任何人都知道使用带有CSRF + AJAX调用的表单的解决方案吗?

1 个答案:

答案 0 :(得分:0)

好的,我解决了在Action中添加CSRF元素,它显示了表单,并在Action中验证了它,然后保存到数据库,而不是在我的Form Class上创建它

为了防止重复代码,我创建了这个类:

class Application_Model_CSRF{

    public static function createCSRF($form, $csrf_salt_name, $field_name="csrf") {
        $element=$form->createElement('hash', $field_name,array(
            'salt' => $csrf_salt_name
        ));
        //Create unique ID if you need to use some Javascript on the CSRF Element
        $element->setAttrib('id',$form->getName().'_'.$element->getId());
        $form->addElement($element);
        return $element;
    }

}

然后,在显示表单的Action中以及在其验证的其他Action中,我使用此代码:

$form    = new Application_Form_Account_Registration();
Application_Model_CSRF::createCSRF($form,"registration");