【问题标题】:How to use Zend Framework Form Hash (token) with AJAX如何在 AJAX 中使用 Zend Framework 表单哈希(令牌)
【发布时间】:2011-01-29 07:22:35
【问题描述】:

我已将 Zend_Form_Element_Hash 包含在一个表单多复选框表单中。我将 jQuery 设置为在单击复选框时触发 AJAX 请求,我通过此 AJAX 请求传递令牌。第一个 AJAX 请求运行良好,但随后的请求失败。

我怀疑它可能是一旦令牌得到验证,它就会从会话中删除(hop = 1)。

对于使用 Zend Framework Hash 保护表单并使用 AJAX 完成其中一些请求,您的攻击计划是什么?

【问题讨论】:

    标签: ajax zend-framework zend-form csrf


    【解决方案1】:

    表单哈希在原则上很棒,但在实践中有点像噩梦。我认为处理此问题的最佳方法是在您发出请求时返回新的哈希值和响应,并根据需要更新表单标记或存储在内存中为您的 javascript。

    新的哈希值可以从表单对象中获得,或者你可以从会话中读取它。

    【讨论】:

    • 我已经从我的类表单中获得了新的令牌值,并且在请求 ajax 后令牌值已经更改,但我的令牌仍然过期
    【解决方案2】:

    您在问题中暗示了正确答案:增加跳数。

    ZF 在线手册中特别提到了这一点,但他们更新了他们的手册,现在我找不到它(笑)-否则我会为你发布链接。

    【讨论】:

    • 可以确认这确实有效,但我不确定它如何影响整个 CSRF 检查的有效性。需要注意的是,我自己扩展了元素并创建了自己的元素,覆盖了initCsrfToken() 方法——不要直接编辑 Zend 文件
    【解决方案3】:

    我最终放弃了使用 Zend_Form_Element_Hash,只是手动创建了一个令牌,向 Zend_Session 注册,然后在提交时检查它。

    form.php

    $myNamespace = new Zend_Session_Namespace('authtoken');
    $myNamespace->setExpirationSeconds(900);
    $myNamespace->authtoken = $hash = md5(uniqid(rand(),1));
    $auth = new Zend_Form_Element_Hidden('authtoken');
    $auth->setValue($hash)
         ->setRequired('true')
         ->removeDecorator('HtmlTag')
         ->removeDecorator('Label');    
    

    controller.php

    $mysession = new Zend_Session_Namespace('authtoken');
    $hash = $mysession->authtoken;
    if($hash == $data['authtoken']){
        print "success";
    } else {
        print "you fail";
    }
    

    这似乎有效,并且仍然使事情保持相对健全和安全。我仍然宁愿使用 Hash 元素,但我似乎无法使其与 AJAX 一起使用。

    谢谢大家。

    【讨论】:

      【解决方案4】:

      有一个解决办法:

      除了要包含数据的表单之外,还要创建一个没有元素的表单。从控制器实例化这两种形式。同样在控制器中,您将元素哈希添加到空表单。两种形式都应发送到愿景。然后,在控制器中的条件“if ($ request-> isXmlHttpRequest ())”中呈现空表单。然后,您使用“getValue ()”方法获取哈希值。该值必须由 Ajax 作为响应发送,然后使用 JavaScript 替换已经过时的哈希值。为散列创建一个空表单的选项是为了避免其他元素(例如验证码)出现问题,如果表单被渲染,它会再次生成其 id,并且还需要替换新信息。验证将单独进行,因为有两种不同的形式。稍后您可以随时重用散列(空)表单。以下是代码示例。

      //In the controller, after instantiating the empty form you add the Hash element to it:
      $hash = new Zend_Form_Element_Hash('no_csrf_foo');
      $hash_form->addElement('hash', 'no_csrf_foo', array('salt' => 'unique'));
      
       //...
      
      //Also in the controller, within the condition "if ($request->isXmlHttpRequest())" you render the form (this will renew the session for the next attempt to send the form) and get the new id value:
      $hash_form->render($this->view);
      $hash_value['hash'] = $hash_form->getElement('no_csrf_foo')->getValue();//The value must be added to the ajax response in JSON, for example. One can use the methods Zend_Json::decode($response) and Zend_Json::encode($array) for conversions between PHP array and JSON.
      
      //---------------------------------------
      
      //In JavaScript, the Ajax response function:
      document.getElementById("no_csrf_foo").value = data.hash;//Retrieves the hash value from the Json response and set it to the hash input.
      

      狮子座

      【讨论】:

        【解决方案5】:

        就是这样处理ajax形式的hash字段:

        class AuthController extends Zend_Controller_Action
        {
            public function init()
            {
                $contextSwitch = $this->_helper->getHelper('contextSwitch');
                $contextSwitch->addActionContext('index', 'json')
                              ->initContext();
            }
        
            public function loginAction()
            {
                $form = new Application_Form_Login();
                $request = $this->getRequest();
        
                if ($request->isPost()) {
                    if ($form->isValid($request->getPost())) {
                        // some code ..
                    } else {
                        // some code ..
        
                        // Regenerate the hash and assign to the view
                        $reservationForm->hash->initCsrfToken();
                        $this->view->hash = $reservationForm->hash->getValue();
                    }
                }
                $this->view->form = $form;
            }
        }
        

        然后在你的视图脚本中..

        <? $this->dojo()->enable()
                        ->requireModule('dojox.json.query')
                        ->onLoadCaptureStart() ?>
        function() {
            var form = dojo.byId("login_form")
            dojo.connect(form, "onsubmit", function(event) {
                dojo.stopEvent(event);
        
                var xhrArgs = {
                    form: this,
                    handleAs: "json",
                    load: function(data) {
                        // assign the new hash to the field
                        dojo.byId("hash").value = dojox.json.query("$.hash", data);
        
                        // some code ..
                    },
                    error: function(error) {
                        // some code ..
                    }
                }
                var deferred = dojo.xhrPost(xhrArgs);
            });
        }
        <? $this->dojo()->onLoadCaptureEnd() ?>
        

        希望还不算太晚:D

        【讨论】:

        • 这里重要的部分是调用 $hashElement->initCsrfToken();在获得价值之前。
        【解决方案6】:

        如果您想在 ajax 端使用表单验证器,请使用以下代码:

        Myform.php

        class Application_Form_Myform extends Zend_Form
        { 
            # init function & ... 
            public function generateform($nohash = false)
            { 
                # Some elements
                if(!$nohash)
                {
                   $temp_csrf = new Zend_Session_Namespace('temp_csrf'); 
                   $my_hash = new Zend_Form_Element_Hash ( 'my_hash' );
                   $this->addElement ( $my_hash , 'my_hash');  
                   $temp_csrf->hash = $my_hash->getHash();
                }
                # Some other elements
            }
        }
        

        AjaxController.php

        class AjaxController extends Zend_Controller_Action
        { 
            // init ... 
            public function validateAction()
            { 
                 # ... 
                 $temp_csrf = new Zend_Session_Namespace('temp_csrf');
                 if($temp_csrf->hash == $params['received_hash_from_client'])
                 {
                     $Myform     = new Application_Form_Myform(); 
                     $Myform->generateform(true);
                     if($AF_Bill->isValid($params))
                     {
                         # Form data is valid
                     }else{
                         # Form invalid
                     }
                 }else{
                     # Received hash from client is not valid
                 }
                 # ... 
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2012-03-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-07
          • 2019-05-02
          • 2019-05-09
          • 1970-01-01
          相关资源
          最近更新 更多