PHP: Stop a Form from being accidentally reprocessed when Back is pressed
Asked Answered
E

6

5

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.

Elbowroom answered 29/10, 2009 at 21:54 Comment(2)
Why do you want to implement this without sessions? You will probably need some kind of server-side storage to detect the duplicate post.Jopa
See below where I suggest storing a token in a database along with whether or not its been used yet. This is definitely some kind of server-side storage, but not sessions.Diastrophism
E
2

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.

Elbowroom answered 2/11, 2009 at 17:6 Comment(2)
Hmm, I'm surprised you can answer your own questions on SO. Should most likely just UPDATE your main question to include the solution.Cathouse
"It's also perfectly fine to ask and answer your own question" ( 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.Elbowroom
G
6

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.

Gaultheria answered 29/10, 2009 at 23:7 Comment(0)
E
2

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.

Elbowroom answered 2/11, 2009 at 17:6 Comment(2)
Hmm, I'm surprised you can answer your own questions on SO. Should most likely just UPDATE your main question to include the solution.Cathouse
"It's also perfectly fine to ask and answer your own question" ( 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.Elbowroom
D
1

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.

Diastrophism answered 29/10, 2009 at 23:33 Comment(4)
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.Elbowroom
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 ;)Diastrophism
For the sake of this Question page, perhaps someone should mark a comprehensive answer involving sessions and session-less database tokens.Elbowroom
Phil: you could always answer the question that way yourselfDiastrophism
O
1

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.

Osteoid answered 17/11, 2009 at 20:58 Comment(1)
This makes a lot of sense as wellElbowroom
A
0

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

Actuate answered 29/10, 2009 at 22:6 Comment(1)
Can you confirm that this works the same way in all browsers?Elbowroom
T
-1

Try this :

<SCRIPT type="text/javascript">
    window.history.forward();
</SCRIPT>
Terpstra answered 2/10, 2012 at 6:16 Comment(3)
This is a PHP question, not javascript.Chenault
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post.Chenault
I have tried above code in my online exam page (PHP) .Which prevented the action of back button,I know its against rules to disable back button . There is no point if the candidate can go back and answer the question again(in the case of online exam ). It worked for me .Terpstra

© 2022 - 2024 — McMap. All rights reserved.