简体   繁体   中英

Zend Form - multiple forms in one page and (CSRF) token validations

I use Zend-Form to generate my forms in my project.

First: How do you handle multiple forms on the same page, and only post the form that is submitted?

Second: When I have two forms on the same page the token will only validate the topmost rendered form in the HTML. The second form with get a "Token does not match" error, thus making the form unable to post. How do you give each form a unique token that does not conflict with the others?

Sincerely, Why

When I have two forms on the same page the token will only validate the topmost rendered form in the HTML. The second form with get a "Token does not match" error, thus making the form unable to post. How do you give each form a unique token that does not conflict with the others?

Tokens on multiple forms are not possible with the current implementation (see initCsrfValidator ).

I suggest you generate your own token, store it in the session (with the form ID) and validate it yourself.

I found this question while trying to have two forms on the same page using Zend_Form_Element_Hash . There are two ways to accomplish this, and both are mentioned in the documentation :

The name of the hash element should be unique. We recommend using the salt option for the element- two hashes with same names and different salts would not collide

So...

  1. Use a unique name for each Hash element
  2. Use a unique salt value for each Hash element

I actually just fixed a similar problem where I was generating several copies of the same form with csrf protection. What was happening was that only the last form created had the correct csrf token.

The sloppy way to deal with this is to change the hop in the Zend library (in the Zend_Form_Element_Hash file) so that tokens don't expire after 1 refresh or page load. It's a really easy way to solve the problem but only works if you know how many times a page will load. This is the bandaid solution

The RIGHT way to do this is once the page has loaded do an ajax call to get a new refreshed token. Then using your javascript library (jquery is probably the simplest) and find ALL instances of the token and replace them all with the new one.

So in terms of code, it would look like this: Controller:

$form->hash->initCsrfToken();

$this->view->hash = $form->hash->getValue();

In your js file (if you're using jquery)

$(.hash).replaceWith('HiddenHtmlPart1'. =hash. 'HiddenHtmlPart2'); The important part is for the selector to select ALL the hidden elements. Then you just need to replace the inside of the hidden element. The same idea applies to other js libraries although it would involve different methods.

I'm running into the same situation of

When I have two forms on the same page the token will only validate the topmost rendered form in the HTML. The second form with get a "Token does not match" error, thus making the form unable to post. How do you give each form a unique token that does not conflict with the others?

A possible solution is to have a separate form only for token generation and validation. Then in the HTML each form has its own token element but with same values. If you submit one form, then validate this token element with the form you used to generate it. If you're using a mix of ajax form and a classical POST form, then you can send a new token in the response and assign it to each token element.

//Finally set the response token
    $form->getElement('token')->render();   //Need to call render in order to regenerate the token
    $response['token'] = $form->getElement('token')->getValue();
    $this->_helper->json($response);

And in jquery you can have something like $('._token').val(response.token)

In fact it is quite easy and even better than having to add a Zend_Form_Element_Hash to each form.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM