17

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

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

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

4

6 回答 6

10

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

表单.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');    

控制器.php

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

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

谢谢大家。

于 2010-03-30T03:52:06.120 回答
8

这就是处理 ajax 形式的哈希字段的方法:

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

于 2011-03-11T01:21:31.807 回答
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.

狮子座

于 2010-04-01T04:30:12.847 回答
2

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

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

于 2010-03-21T15:51:52.807 回答
1

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

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

于 2010-03-25T07:09:03.417 回答
0

如果您想在 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
         }
         # ... 
    }
}
于 2014-03-16T08:59:34.533 回答