Are there techniques to prevent double submissions in stateless web applications?
Asked Answered
I

3

9

I want to implement double submission prevention in an existing java web application (struts actually). Architecture wise we are talking about 2 to N possible application servers (tomcat) and one single database server (mysql). The individual servers do not know each other and are not able to exchange messages. In front of the application servers there is a single load balancer which has the ability to do sticky sessions.

So basically there are two kinds of double submission prevention client side and server side. If possible I want to go server-side because all client side techniques seem to fail if people disable cookies and/or javascript in their browsers.

This leaves me with the idea of doing some kind of mutex-like synchronisation via database locks. I think it may be possible to calculate a checksum of the user entered data and persisting it to a dedicated database table. On each submit the application would have to check for presence of an equal checksum which would indicate that the given submission is a duplicate. Of course the checksums in this table have to be cleared periodically. The problem is the whole process of checking whether there is a duplicate checksum already in the database and inserting the checksum if there is none is pretty much a critical section. Therefore the checksum table has to be locked beforehand and unlocked again after the section.

My deadlock and bottle neck alarm bells start to ring when I think about table locks. So my question is: Are there saner ways to prevent double submissions in stateless web applications?

Please note that the struts TokenInterceptor can not be applied here because it fails miserably when cookies are disabled (it relies on the HTTP session which simply isn't present without session cookies).

Indiscerptible answered 19/9, 2011 at 16:8 Comment(6)
Do you already know the POST-REDIRECT-GET pattern? Isn't it useful for your case?Thumbprint
Wouldn't stateless double submit prevention be impossible? Isn't the double submit token state, wherever it is stored? An identical transaction might not be doubly-submitted, it might simply be an identical transaction. So checking your data layer probably wouldn't work either.Vandavandal
Are you anticipating a lot of users w/o JavaScript and w/o cookies? Are you sure the ROI is worth the effort? In any case, you've pretty much backed yourself into the corner of relying on a DB hash, since you can't guarantee that the second click would be handled by the same server, nor that application state would replicate quickly enough. You'd also need to expire those hash entries pretty quickly, since it could be a legitimate re-submission. Maybe keep a large in-memory map instead using any of several implementations (or in-memory DB)?Patrology
@Thumbprint this pattern is useful but not in my situation where the server reply to the submission can take some time and the users usually would submitting the same request again.Indiscerptible
@DaveNewton I do not know why but there seem to be a lot of users out there without enbaled cookies and/or JavaScript. A previous simple solution relying on HTTP session attributes did fail for this reason.Indiscerptible
@itti I understand, I have misinterpreted your question. Sorry for the mess :)Thumbprint
I
7

A simpler DB based solution would be something like this. This can be made generic across multiple forms as well.

  • Have a database table that can be used to store tokens.
  • When an new form is displayed - insert a new row into the token table and add the token as a hidden field in the form.
  • When you get a form submit do a select for update on the row corresponding to the token you received as a part of the form.
  • If the row still exists then this is the first submit. Process the submit and delete the row.
  • If the row doesn't exist then the form has already been processed - you can return an error.
Icicle answered 19/9, 2011 at 16:27 Comment(1)
I will take a shot at this solution as you suggest row level locks instead of table locks. This seems to make more sense to me than my approach.Indiscerptible
S
1

The classic technique to prevent double submissions is to assign two IDs (both as "hidden" field in HTML Form tag) - one "session-ID" which stays the same from login to logout...

The second ID changes with every submission... server-side you only need to keep track of the "current valid ID" (session-specific)... if you get a "re-submission" (by click-happy-user or a "refresh-button" or a "back-button" or...) then that wouldn't match the current ID... this way you know: this submission should be discarded and a new ID is generated and sent back with the answer. Some implementations use an ID that is inremented on every submission which eases a bit the check/kepp track part but that could be vulnerable to "guessing" (security concern)... I like to generate cryptographically strong IDs for this kind of protection...

IF you have a load-balanced environment with sticky session then you only need to keep track of the ID on the server itself (in-memory)... but you can certainly store the ID in the DB... since you store it together with the session ID the lock would be on "row level" (not table level) which should be ok.

The way you described goes one step further by examining the content... BUT I see the content part more on the "application logic" level than on the "re-submission prevention level" since it depends on the app logic whether it wants to accepts the same data again...

Sibyl answered 19/9, 2011 at 16:21 Comment(2)
Not helpful if there's no session, which is what the OP posits.Patrology
What the OP posts is "load-balancing with sticky sessions" which in turn means there is some sort of session AND thus the above mechanism works...Sibyl
C
0

What if you work with sticky sessions then you would be fine with some TokenManagement. There exist a DoubleClickFilter which you can add to your web.xml.

Since you have sticky sessions there is no need for a Cross-Tomcat-Solution.

Cenis answered 19/9, 2011 at 16:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.