1

我的程序使用 Zend Framework,我想使用 Zend_Form_Element_Hash 保护用户免受 CSRF 的影响。但这似乎不起作用。

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

    $exithash = new Zend_Form_Element_Hash('hihacker', array('salt' => 'exitsalt'));
    $this->addElement($exithash);

在我的控制器 Auth 插件中,我做

    $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_Form_Exit,将其存储在注册表中并从中回显,从我的站点“在新选项卡中”打开页面也会导致所有此类受 csrf 保护的表单停止工作。

那么,我该如何保护呢?

4

3 回答 3

1

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

如果您因为每次都更改哈希而无法“验证”表单,那么您执行任务的顺序错误,需要重新评估您的流程。

于 2009-11-07T06:58:21.713 回答
1

您应该检查 Zend_Form_Element_Hash 是否能够将散列保存到 Zend_Session_Namespace。根据该元素的文档,这是预期的行为:Zend Documentation

于 2009-10-26T17:28:10.280 回答
-1

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

我从每个用户的密码哈希和其他参数生成一个哈希。在他更改密码之前,每个用户的哈希值都是不变的:

   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);
于 2009-10-26T17:29:18.627 回答