2010-03-19 8 views
17

Ho incluso Zend_Form_Element_Hash in un modulo modulo multiplecheckbox. Ho impostato jQuery per attivare una richiesta AJAX quando si fa clic su una casella di controllo, ho passato il token con questa richiesta AJAX. La prima richiesta AJAX funziona alla grande, ma quelli successivi falliscono.Come utilizzare Zend Framework Form Hash (token) con AJAX

Sospetto che possa essere una volta che il token è stato convalidato e quindi rimosso dalla sessione (hop = 1).

Quale sarebbe il tuo piano di attacco per proteggere un modulo con Zend Framework Hash utilizzando ancora AJAX per completare alcune di queste richieste?

risposta

9

Ho infine abbandonato l'utilizzo di Zend_Form_Element_Hash e ho appena creato un token manualmente, l'ho registrato con Zend_Session e quindi controllato dopo l'invio.

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

Questo sembra funzionare ed ancora mantiene le cose relativamente sano e sicuro. Preferisco ancora usare l'elemento Hash, ma non riesco a farlo funzionare con AJAX.

Grazie a tutti.

2

Gli hash della forma sono grandi in linea di principio e un po 'di incubo nella pratica. Penso che il modo migliore per gestirlo sia restituire il nuovo hash con la risposta quando si effettua una richiesta e aggiornare il markup del modulo o archiviare in memoria il proprio javascript come appropriato.

Il nuovo hash può essere disponibile dall'oggetto modulo oppure è possibile leggerlo dalla sessione.

+0

Sono già ottenere nuovo valore simbolico dal mio classe Form e il valore del token sono già stati modificati dopo richiesta ajax ma il mio token è ancora scaduto tdhong

1

Hai suggerito la risposta giusta nella tua domanda: aumenta il numero di hop.

C'era una menzione specifica di questo nel manuale ZF online, ma hanno aggiornato i loro manuali e ora non riesco a trovarlo (sorriso) - altrimenti avrei postato il link per te.

+0

Può confermare th è funziona, ma non sono sicuro di come influenzi l'efficacia del controllo CSRF complessivo. Una nota è che ho esteso l'elemento da solo e creato il mio, sovrascrivendo il metodo 'initCsrfToken()' - non modificare direttamente i file di Zend – dKen

4

C'è una soluzione:

Creare, oltre al modulo che conterrà i dati, una forma senza elementi. Dal controller si istanziano le due forme. Anche nel controller, si aggiunge l'hash dell'elemento al modulo vuoto. Entrambe le forme dovrebbero essere inviate alla visione. Quindi, nella condizione "if ($ request-> isXmlHttpRequest())" nel controller, si esegue il rendering del modulo vuoto. Quindi, si prende il valore hash con il metodo "getValue()". Questo valore deve essere inviato in risposta da Ajax e quindi utilizzare JavaScript per sostituire il valore hash che è già obsoleto. L'opzione per creare un modulo vuoto per l'hash è di evitare problemi con altri elementi come captcha che avrebbe il suo id generato di nuovo se il modulo fosse reso, e avrebbe anche bisogno di avere le nuove informazioni sostituite. La convalida verrà eseguita separatamente perché ci sono due forme distinte. Successivamente puoi riutilizzare il modulo (vuoto) quando lo desideri. I seguenti sono esempi del codice.

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

Ecco come ha gestito campo hash in forma 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; 
    } 
} 

E poi nello script 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() ?> 

Spero che non sia troppo tardi: D

+0

La parte importante qui è chiamare 01a$ hashElement-> initCsrfToken(); prima di ottenere il valore. –

0

Se si ou desidera utilizzare modulo validatore in uso Ajax seguente codice:

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 
     } 
     # ... 
    } 
}