2010-03-19 17 views
17

He incluido Zend_Form_Element_Hash en un formulario de formulario de recuadro múltiple. Tengo jQuery configurado para disparar una solicitud AJAX cuando se hace clic en una casilla de verificación, paso el token con esta solicitud AJAX. La primera solicitud de AJAX funciona bien, pero las siguientes fallan.Cómo utilizar Zend Framework Form Hash (token) con AJAX

Sospecho que puede ser una vez que el token ha sido validado, se elimina de la sesión (hop = 1).

¿Cuál sería su plan de ataque para proteger un formulario con Zend Framework Hash pero utilizando AJAX para completar algunas de estas solicitudes?

Respuesta

9

Finalmente abandoné el uso de Zend_Form_Element_Hash y acabo de crear un token de forma manual, lo registré con Zend_Session y luego lo revisé en el momento del envío.

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"; 
} 

Esto parece funcionar y todavía mantiene las cosas relativamente sano y seguro. Todavía prefiero utilizar el elemento Hash, pero parece que no puedo hacerlo funcionar con AJAX.

Gracias a todos.

2

Los hash de forma son geniales en principio y un poco pesadilla en la práctica. Creo que la mejor manera de manejar esto es devolver el nuevo hash con la respuesta cuando realiza una solicitud, y actualizar el formulario de marcado o almacenar en la memoria para su javascript, según corresponda.

El hash nuevo puede estar disponible desde el objeto de formulario o puede leerlo desde la sesión.

+0

ya estoy conseguir nuevo valor simbólico de mi La forma de clase y el valor del token ya han cambiado después de solicitar ajax, pero mi token aún expiró tdhong

1

Indicó la respuesta correcta en su pregunta: aumente el recuento de saltos.

Hubo una mención específica de esto en el manual de ZF en línea, pero actualizaron sus manuales y ahora no puedo encontrarlo (sonreír); de lo contrario, habría publicado el enlace por usted.

+0

Puede confirmar th funciona, pero no estoy seguro de cómo afecta la efectividad del chequeo CSRF en general. Una nota es que amplié el elemento yo mismo y creé el mío, sobrescribiendo el método 'initCsrfToken()' - no edito los archivos Zend directamente – dKen

4

hay una solución:

Cree, además de la forma que contendrá los datos, una forma sin elementos. Desde el controlador crea una instancia de las dos formas. También en el controlador, agrega el hash del elemento al formulario vacío. Ambas formas deben enviarse a la visión. Luego, en la condición "if ($ request-> isXmlHttpRequest())" en el controlador se muestra el formulario vacío. Luego, toma el valor hash con el método "getValue()". Este valor debe enviarse en respuesta por Ajax y luego usar JavaScript para reemplazar el valor de hash que ya está obsoleto. La opción de crear un formulario vacío para el hash es evitar problemas con otros elementos, como captcha, que generarían su id nuevamente si se procesara el formulario, y también necesitarían reemplazar la nueva información. La validación se realizará por separado porque hay dos formas distintas. Más tarde puede reutilizar el hash (vacío) formulario siempre que lo desee. Los siguientes son ejemplos del código.

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

8

es así de manejarse campo de hash en ajax formulario:

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; 
    } 
} 

Y luego, en el script de vista ..

<? $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() ?> 

espero que no sea demasiado tarde: D

+0

La parte importante aquí es llamar al $ hashElement-> initCsrfToken(); antes de obtener el valor. –

0

If y ou quiere utilizar el formulario de validación en uso lado ajax siguiente código:

miformulario.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 
     } 
     # ... 
    } 
} 
Cuestiones relacionadas