Zend framework 如何使用Zend框架保护用户免受跨站点请求伪造?

Zend framework 如何使用Zend框架保护用户免受跨站点请求伪造?,zend-framework,zend-form,csrf,Zend Framework,Zend Form,Csrf,我的程序使用Zend框架,我想使用Zend_Form_Element_哈希保护用户免受CSRF的影响。但它似乎不起作用 例如,我的注销表单代码是 $exithash = new Zend_Form_Element_Hash('hihacker', array('salt' => 'exitsalt')); $this->addElement($exithash); 在控制器的身份验证插件中 $exitForm = new R00_Form_Exit();

我的程序使用Zend框架,我想使用Zend_Form_Element_哈希保护用户免受CSRF的影响。但它似乎不起作用

例如,我的注销表单代码是

    $exithash = new Zend_Form_Element_Hash('hihacker', array('salt' => 'exitsalt'));
    $this->addElement($exithash);
在控制器的身份验证插件中

    $exitForm = new R00_Form_Exit();

    if ($exitForm->isValid($_POST)) {
        R00_Auth::logout(); // a wrapper for Zend_Auth::getInstance()->clearIdentity();

        Zend_Registry::get('Log')->info('User has logged out');

        $this->setRedirect($request); // redirect to the current page
    }
在我的布局中

    echo new R00_Form_Exit();
好的。但它不工作,我点击表单的提交按钮,页面重新加载,但身份仍然存在

正如我所意识到的,Zend_Form_Element_Hash为每次表单创建新的哈希值,并将来自用户的哈希与来自会话的哈希(最后生成的哈希)进行比较!这很奇怪。例如,即使我尝试在我的应用程序中只创建一个R00_表单_出口,将其存储在注册表中并从中回送,从我的站点“在新选项卡中”打开一个页面将导致所有此类受csrf保护的表单停止工作


那么,如何保护?

您应该检查Zend\u Form\u元素\u散列是否能够将散列保存到Zend\u Session\u命名空间中。根据该元素的文档,这是预期的行为:

您应该检查Zend\u Form\u元素\u散列是否能够将散列保存到Zend\u Session\u命名空间中。根据该元素的文档,这是预期的行为:

这里我提出了我自己的解决方案。但它仍然不是很酷,所以我很高兴听到关于这方面的任何其他更好的解决方案和评论

我根据每个用户的密码哈希和其他参数生成一个哈希。哈希值对于每个用户都是恒定的,直到他更改密码:

   public function getSecurityHash() {
          return md5( $this->getIntID() . $this->getLogin() . 'R00SuperSalt' );
   }
并且,以以下形式:

    $exithash = new Zend_Form_Element_Hidden('exithash');
    $exithash->setValue( R00_Auth::getUser()->getSecurityHash() )
             ->addValidator('Identical', false, array(
                R00_Auth::getUser()->getSecurityHash()
              ))
             ->setDecorators(array('ViewHelper'))
             ->setRequired(true);

在这里,我提出了自己的解决方案。但它仍然不是很酷,所以我很高兴听到关于这方面的任何其他更好的解决方案和评论

我根据每个用户的密码哈希和其他参数生成一个哈希。哈希值对于每个用户都是恒定的,直到他更改密码:

   public function getSecurityHash() {
          return md5( $this->getIntID() . $this->getLogin() . 'R00SuperSalt' );
   }
并且,以以下形式:

    $exithash = new Zend_Form_Element_Hidden('exithash');
    $exithash->setValue( R00_Auth::getUser()->getSecurityHash() )
             ->addValidator('Identical', false, array(
                R00_Auth::getUser()->getSecurityHash()
              ))
             ->setDecorators(array('ViewHelper'))
             ->setRequired(true);

每次调用哈希生成器时,在指定的会话名称空间和位置中,它应该是不同的。这就是为什么只有在构建实际表单时才创建哈希。这样做会将散列存储一个跃点(意味着页面加载),然后忘记它(特别是在为用户重新生成表单时)这就是CSRF的目的!通过使过期的表单无效来防止表单劫持。(基本上)


如果由于哈希每次更改而无法“验证”表单,则表明您正在以错误的顺序执行任务,需要重新评估流程。

每次调用哈希生成器时,在指定的会话名称空间和位置中,应该是不同的。这就是为什么只有在构建实际表单时才创建哈希。这样做会将散列存储一个跃点(意味着页面加载),然后忘记它(特别是在为用户重新生成表单时)这就是CSRF的目的!通过使过期的表单无效来防止表单劫持。(基本上)


如果由于哈希值每次都发生更改而无法“验证”表单,则表明您以错误的顺序执行任务,需要重新评估流程。

如何检查?我没有任何线索:)顺便说一句,我使用带有默认适配器的Zend_缓存,它使用Zend_会话,工作正常。所以我认为没有问题,只要尝试转储$\u会话,它应该包含来自所有Zend\u会话名称空间的所有值。如果哈希表单元素中有某个值,请检查它在两个请求中是否保持相同。否,它不相同:([“Zend_Form_element_Hash_exitsalt_hihacker”][“Hash”]在一个页面上是“66CB1454663F62C7CF22899CC8807E”,在另一个页面上是“405a7413ff1b58ae966dbfac4a1b9f16”,在ZF_element_哈希的代码中:$session->->setExpirationHops(1) .是的,它每次都会重新生成哈希!呃,要么它不可用,要么我没有想法我该怎么检查?我没有线索:)顺便说一句,我使用Zend_缓存和默认适配器,它使用Zend_会话,工作正常。所以我认为没有问题,只要尝试转储$_会话,它应该包含所有Zend_会话名称空间中的所有值。如果哈希表单元素中有某个值,请检查它在两个请求中是否保持相同。不,它不一样:([“Zend_Form_Element_Hash_exitsalt_hihacker”[“Hash”]是一页上的“66cb145466361f62c7cf22899cc8807e”,另一页上的“405a7413ff1b58ae966dbfac4a1b9f16”,在ZF_Element_Hash的代码中:$session->setExpirationHops(1)。是的,它每次都会重新生成Hash!呃,要么它不可用要么我不知道$exithash->setValue(getUser::getUser()->getSecurityHash())->addValidator('idential',false,array(R00_Auth::getUser()->getSecurityHash());这不是完全破坏了哈希的效果吗?我的意思是,这就像是(“foo”==“foo”)不,它不是:)代码在类的init()中,来自用户的所有输入将填充到表单的值中,因此->setValue()只影响隐藏元素中的值这不是CSRF!CSRF令牌在每个会话的基础上必须不同(不确定,但可能甚至在每个请求的基础上也不同)。$exithash->setValue(R00_Auth::getUser()->getSecurityHash())->addValidator('idential',false,array(R00_Auth::getUser()->getSecurityHash());这不是完全破坏了哈希的效果吗?我的意思是,这就像(“foo”==“foo”)不,它不是:)代码在类的init()中。在->isValid()中,用户的所有输入都填充到表单的值中,所以->setValue()仅影响隐藏元素中的值这不是CSRF!CSRF令牌在每个会话的基础上必须不同(不确定,但可能甚至在每个请求的基础上)。