0

I found many questions on SO regarding the question how to prevent double form submission:

The answer seems to be:

  1. Disable the submit button as soon as the user clicks it.
  2. Follow a POST-Redirect-GET pattern to prevent POSTs when the user refreshes the page
  3. Prevent double submission on the server side when JS is disabled.

I am interested how step 3 can be implemented. I found here

The common solution is to generate a token on the server every time you generate a form. Store the token on the server, add it as a hidden field to the form, and delete it once you get a form submission with that token.

If you get a form submission without a valid token, it means that the form has already been submitted and ignore it.

An example implementation of this may be found here:

function isTokenValid($token){
  if(!empty($_SESSION['tokens'][$token])){
    unset($_SESSION['tokens'][$token]);
    return true;
  }
  return false;
}

// Check if a form has been sent
$postedToken = filter_input(INPUT_POST, 'token');
if(!empty($postedToken)){
  if(isTokenValid($postedToken)){
    // Process form
  }
  else{
    // Do something about the error
  }
}

However, I do not understand why this should work. If a user clicks a button twice (and we have no JS disable button protection), then I believe its possible that both requests are executed parallel. If the validation check happens simultaneously then both request would pass on the server side.

The only way I can image to prevent this is by using a database with transactions. But is it really that complicated? Or am I overlook something?

Adam
  • 25,960
  • 22
  • 158
  • 247
  • 1
    Both requests would have to be sent and ARRIVE at the same time to the server. We are talking microseconds right? I don't think this repeatable. You can implement the token using a database btw. – bassxzero Jul 26 '19 at 14:43
  • I don't see it very likely that a user manages to send two identical requests that hits the server in the _exact_ same time (computers are fast, so "exact" is most likely down to nano seconds). There's also no reason for this token to ever exist in a database. It's a one-time-only token between PHP (stored in a session) and the front end. – M. Eriksson Jul 26 '19 at 14:48
  • Delete the token asap before any specific form handling process. If you use a database it will lock the token record during the delete/update anyway, so don't worry about that... – Damien Legros Jul 26 '19 at 14:49
  • @MagnusEriksson if you use a database to store the token in, then you can check on the backend without having to worry about race conditions. Simply checking if the token is still in the session, might lead to race conditions. But I agree of course, that this race condition is very unlikely to happen. – Adam Jul 26 '19 at 16:15
  • Considering that it's the same user that has to make these two identical requests at the _exact_ the same time (down to nth of a second), I would guess that statistically, it isn't even an issue. I would just stick to sessions and wouldn't think about race conditions until it actually happens. You're basically trying to solve a theoretical problem that will most likely never happen – M. Eriksson Jul 27 '19 at 09:36

0 Answers0