Как использовать Zend Framework Form Hash (токен) с AJAX - PullRequest
17 голосов
/ 19 марта 2010

Я включил Zend_Form_Element_Hash в форму множественной проверки формы. У меня есть jQuery для запуска AJAX-запроса, когда флажок установлен, я передаю токен с этим AJAX-запросом. Первый запрос AJAX отлично работает, но последующие не удаются.

Я подозреваю, что это может быть, как только токен был проверен, он затем удаляется из сеанса (прыжок = 1).

Каков будет ваш план атаки на защиту формы с помощью Zend Framework Hash, но с использованием AJAX для выполнения некоторых из этих запросов?

Ответы [ 6 ]

9 голосов
/ 30 марта 2010

Я окончательно отказался от использования 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.

Спасибо всем.

8 голосов
/ 11 марта 2011

Вот как обрабатывается хеш-поле в виде 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

4 голосов
/ 01 апреля 2010

Есть решение:

Создайте, помимо формы, которая будет содержать данные, форму без элементов. Из контроллера вы создаете две формы. Также в контроллере вы добавляете хеш элемента в пустую форму. Обе формы должны быть отправлены в видение. Затем в условии «if ($ request-> isXmlHttpRequest ())» в контроллере вы отображаете пустую форму. Затем вы берете значение хеша с помощью метода "getValue ()". Это значение должно быть отправлено в ответ Ajax, а затем использовать JavaScript для замены устаревшего хеш-значения. Возможность создать пустую форму для хеша состоит в том, чтобы избежать проблем с другими элементами, такими как капча, которая будет генерировать свой идентификатор снова, если форма будет отображена, и также потребуется заменить новую информацию. Проверка будет выполняться отдельно, потому что есть две разные формы. Позже вы можете повторно использовать хэш (пустую) форму, когда захотите. Ниже приведены примеры кода.

//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.

Leo

2 голосов
/ 21 марта 2010

Форма хэшей в принципе великолепна и на практике немного кошмарна.Я думаю, что лучший способ справиться с этим - вернуть новый хеш с ответом, когда вы делаете запрос, и соответствующим образом обновить разметку формы или сохранить ее в памяти для вашего javascript.из объекта формы, или вы можете прочитать его из сеанса.

1 голос
/ 25 марта 2010

Вы намекали на правильный ответ в своем вопросе: увеличьте количество прыжков.

В руководстве по ZF было упоминание об этом, но они обновили свои руководства, и теперь я не могу его найти (ухмыляясь) - иначе я бы опубликовал ссылку для вас.

0 голосов
/ 16 марта 2014

Если вы хотите использовать валидатор формы в 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
         }
         # ... 
    }
}
...