2010-03-19 5 views
17

Ich habe Zend_Form_Element_Hash in ein Formular mehrere Kontrollkästchen-Formular enthalten. Ich habe jQuery festgelegt, um eine AJAX-Anfrage abzubrechen, wenn ein Kontrollkästchen angeklickt wird, übergebe ich das Token mit dieser AJAX-Anfrage. Die erste AJAX-Anfrage funktioniert gut, aber die nachfolgenden AJAX-Anfragen schlagen fehl.Wie verwendet man Zend Framework Form Hash (Token) mit AJAX

Ich vermute, es kann sein, sobald das Token validiert wurde, wird es dann aus der Sitzung entfernt (Hop = 1).

Was wäre Ihr Angriffsplan, um ein Formular mit Zend Framework Hash zu sichern, aber mit AJAX, um einige dieser Anfragen zu vervollständigen?

Antwort

9

Ich habe schließlich mit Zend_Form_Element_Hash verlassen und nur ein Token manuell erstellt, registriert es mit Zend_Session und dann überprüft es bei der Einreichung.

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

Dies scheint und hält die Dinge relativ gesund und sicher noch zu arbeiten. Ich würde immer noch lieber das Hash-Element verwenden, aber ich kann nicht scheinen, dass es mit AJAX funktioniert.

Danke allen.

2

Formhashes sind im Prinzip großartig und in der Praxis ein Albtraum. Ich denke, der beste Weg, dies zu handhaben, ist, den neuen Hash mit der Antwort zurückzugeben, wenn Sie eine Anfrage stellen, und das Formular-Markup zu aktualisieren oder im Speicher für Ihr Javascript zu speichern, wie passend.

Der neue Hash kann über das Formularobjekt verfügbar sein, oder Sie können ihn aus der Sitzung lesen.

+0

Ich bin schon neuen Token-Wert erhalten von meinem Klassenform und der Token-Wert haben sich bereits nach der Anfrage ajax geändert, aber mein Token ist noch abgelaufen tdhong

1

Sie haben die richtige Antwort in Ihrer Frage angedeutet: Erhöhen Sie die Anzahl der Hops.

Im ZF-Handbuch wurde dies ausdrücklich erwähnt, aber sie haben ihre Handbücher aktualisiert und ich kann sie nicht finden (grins) - sonst hätte ich den Link für Sie gepostet.

+0

Kann th bestätigen Es funktioniert, aber ich bin mir nicht sicher, wie es die Effektivität der CSRF-Überprüfung insgesamt beeinflusst. Eine Anmerkung ist, dass ich das Element selbst erweitert und mein eigenes erstellt habe, indem ich die 'initCsrfToken()' Methode überschrieben habe - bearbeite die Zend Dateien nicht direkt – dKen

4

Es gibt eine Lösung:

erstellen, neben der Form, die die Daten, ein Formular ohne Elemente enthalten wird. Von der Steuerung aus instanziieren Sie die zwei Formen. Auch im Controller fügen Sie den Element-Hash dem leeren Formular hinzu. Beide Formulare sollten an die Vision gesendet werden. In der Bedingung "if ($ request-> isXmlHttpRequest())" im Controller rendern Sie dann das leere Formular. Dann nehmen Sie den Hash-Wert mit der Methode "getValue()". Dieser Wert muss als Antwort von Ajax gesendet werden und dann mit JavaScript den Hash-Wert ersetzen, der bereits veraltet ist. Die Option, ein leeres Formular für den Hash zu erstellen, besteht darin, Probleme mit anderen Elementen wie Captcha zu vermeiden, deren ID beim Rendern des Formulars erneut generiert würde. Außerdem müsste die neue Information ersetzt werden. Die Validierung wird getrennt durchgeführt, da es zwei verschiedene Formen gibt. Später können Sie das Hash-Formular (leer) jederzeit wiederverwenden. Die folgenden sind Beispiele für den Code.

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

Das ist, wie Hash-Feld in Ajax-Formular behandelt:

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

Und dann in View Skript ..

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

Hoffe, dass es nicht zu spät ist: D

+0

Der wichtige Teil hier ist der Aufruf $ hashElement-> initCsrfToken(); bevor Sie den Wert erhalten. –

0

Wenn y ou will folgende Code Form Validator in Ajax-Seite Gebrauch verwenden:

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