Как использовать Zend Framework Form Hash (токен) с помощью AJAX
Я включил Zend_Form_Element_Hash в форму формы с несколькими точками. У меня есть jQuery, чтобы отключить запрос AJAX при щелчке по флажку, я передаю токен с этим запросом AJAX. Первый запрос AJAX отлично работает, но последующие не работают.
Я подозреваю, что это может быть после того, как токен был проверен, а затем удален из сеанса (hop = 1).
Каким будет ваш план атаки для защиты формы с помощью Zend Framework Hash, но с помощью AJAX для выполнения некоторых из этих запросов?
Ответы
Ответ 1
Я, наконец, отказался от использования 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.
Спасибо всем.
Ответ 2
Как обработать поле хэша в форме 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;
}
}
А затем в вашем представлении script..
<? $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
Ответ 3
Существует решение:
Создайте помимо формы, содержащей данные, форму без элементов. Из контроллера вы создаете экземпляры двух форм. Также в контроллере вы добавляете хэш элемента в пустую форму. Обе формы должны быть направлены в видение. Затем в условии "if ($ request- > isXmlHttpRequest())" в контроллере вы отображаете пустую форму. Затем вы берете хэш-значение с помощью метода getValue(). Это значение должно быть отправлено в ответ Ajax, а затем использовать JavaScript для замены хеш-значения, которое уже устарело. Возможность создания пустой формы для хэша состоит в том, чтобы избежать проблем с другими элементами, такими как captcha, которые будут иметь свой идентификатор, сгенерированный снова, если форма была отображена, а также потребуется заменить новую информацию. Валидация будет выполняться отдельно, поскольку существуют две различные формы. Позже вы можете повторно использовать хэш (пустую) форму, когда захотите. Ниже приведены примеры кода.
//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.
Лео
Ответ 4
Форма хэшей в принципе велика и немного кошмара на практике. Я считаю, что лучший способ справиться с этим - вернуть новый хэш с ответом при создании запроса и обновить разметку формы или сохранить в памяти для вашего javascript, если это необходимо.
Новый хеш может быть доступен из объекта формы, или вы можете прочитать его из сеанса.
Ответ 5
Вы намекали на правильный ответ в своем вопросе: увеличьте количество прыжков.
В справочнике ZF упоминалось об этом отдельно, но они обновили свои руководства, и теперь я не могу его найти (усмешка) - иначе я бы разместил ссылку для вас.
Ответ 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
}
# ...
}
}