views:

533

answers:

6

What is the best way to stop a form from being reprocessed when a user hits a Back button?

I'm following the Post/Redirect/Get pattern, so I don't have a problem if F5 is pushed, but the back button still provides the opportunity to resubmit the form. If this form is a credit card processing page, this is bad.

This question has been asked somewhat here, but the phrasing and answers were of poor quality and not specific to this problem exactly.

I have form.php which submits to itself. If there were no errors in input data upon submission, the user is redirected to form_thanks.php. Hitting back (and "Send" or "Resubmit") once resubmits form.php (BAD!) and then brings them back to form_thanks.php.

Please also include solutions that do not involve using Sessions, if possible.

A: 

I find that back will bring the form to the state it was before the page was redirected, if that is the case, have a hidden input/variable or something which starts with value say true, then once the form is submitted, and if the value is true, change it to false and then submit, else return false

Psytronic
Can you confirm that this works the same way in all browsers?
philfreo
+3  A: 

I would do it a different way. Put up a hidden input with a random string as the value, and when it's submitted store that random string in a session. Set up a simple check to see if they've already posted it and if they have don't accept the input.

Whitey
A: 

Disable the submit button using javascript when user clicks on it. The button will stay disabled even after a 'Back' action.

Lukman
I'm already doing this. This doesn't stop the problem. When you hit "Back", the browser, after confirming that you want to re-post, resends the form data without ever showing the HTML form.
philfreo
+1  A: 

Just thinking out loud here. But what about a variation on post/redirect/get where the final get is not actually the final get ;) But rather, it in turn always automatically forwards to the truly final page, so that should the user hit the back button, they return right back whence they came?

EDIT:

Ok, taking into consideration the OP's comment, here's another idea. The URL for the form submission could be made to require a parameter that is good for only one use. That token would be generated (using MD5 or some such) before the form was submitted and could be stored in a database (in response to somebody else's suggestion you requested a solution without using sessions). After the form is processed, this token would then be flagged in the database as having already been used. So that when the page is returned to with the same token, steps can be taken to prevent the resubmission of the form data to the backend.

George Jempty
That would work except for the fact that browsers' back buttons often have dropdowns that let a user easily jump 2 or more pages back.
philfreo
Under my second suggestion, every time the URL is requested without a token parameter, a token is generated and the form essentially redirects to itself but with this token as part of the URL. Hope this is making sense, I've been up since 5:30 am ;)
George Jempty
Yes, this second solution definitely sounds good.
philfreo
For the sake of this Question page, perhaps someone should mark a comprehensive answer involving sessions and session-less database tokens.
philfreo
Phil: you could always answer the question that way yourself
George Jempty
+1  A: 

This should be done with a single-use token, or a nonce. The php/server should include this token in a hidden form field.

It should store a list of all the recent tokens and each time a form is submitted, it should check to see if the token is in the list of recent valid tokens.

If it's not in the list, then don't reprocess the form.
If it is in the list, then process the form and remove the token from the list.

The tokens can be handled within sessions or just a simple database table without sessions. The tokens should be user-specific though.

This is also the recommended way to avoid CSRF attacks.

philfreo
Hmm, I'm surprised you can answer your own questions on SO. Should most likely just `UPDATE` your main question to include the solution.
Jakub
"It's also perfectly fine to ask and answer your own question" ( http://meta.stackoverflow.com/faq ) and it was suggested that I do this once someone else's answer didn't seem to fully answer the question. It's best to do this in separate questions/answers because that way other people can specifically comment/vote on them and because otherwise the original "question" is confusing for people who find it since it's no longer a question.
philfreo
+1  A: 

Late answer, but one could avoid the processing altogether by using an AJAX-based solution; there wouldn't be an issue with including a nonce with this processing scheme, but by using an asynchronous query which, on success, redirects the user, the requests are not repeated by refreshing, pressing back, or anything other than clicking the button.

It is also easy to implement a mechanism that prevents the button from either being pressed twice or being "locked up" if something happened during the request by embedding into the handler for the request (whether high level with PrototypeJS or jQuery or low level with your handrolled function) the mechanisms to enable and disable the button when the request completes and first fires, respectively.

Dereleased
This makes a lot of sense as well
philfreo