Mar 2, 2009

Prevent Duplicate Form Submission

Duplicate form submissions can occur in many ways :
  • Using Refresh button
  • Using the browser back button to traverse back and resubmit form
  • Using Browser history feature and re-submit form.
  • Malicious submissions to adversely impact the server or personal gains
  • Clicking more than once on a transaction that take longer than usual
Effect :

Think about a online shopping site, You are buying from a online shopping store. You hava submitted the form by clicking submit button screen comes with "Please wait...." and stays for a long you worried and press submit again what happens the first click submitted first shopping and second click requests for the same order again. And you have to pay for same item twice.

This is only the one case you may be pay twice, there are many others factors which can affects.

Solution :
  1. Disable submit button on first time it is clicked.
    This helps prevent duplicate form submission from user aggresion impatient. But not from the others mentioned above.
    E.g. <input type="submit" name="submit" onclick="this.disabled='true';/*your other function calling*/">

  2. Using Struts :
    1. By forwarding twice :

      The easy solution to this problem is to use HTTP redirect after the form submission. Suppose that the CustomerForm submission results in showing a page called Success.jsp. When HTTP redirect is used, the URL in the URL bar becomes /App1/Success.jsp instead of /App1/submitCustomerForm.do. When the page refreshed, it is the Success.jsp that is loaded again instead of App1/submitCustomerForm.do. Hence the form is not submitted again. To use the HTTP redirect feature, the forward is set as follows:

      <forward name=”success” path=”/Success.jsp” redirect=”true” />

      However there is one catch. With the above setting, the actual JSP name is shown in the URL. Whenever the JSP name appears in the URL bar, it is a candidate for ForwardAction. Hence change the above forward to be as follows:

      <forward name=”success” path=”/GotoSuccess.do” redirect=”true” />

      Where GotoSuccess.do is another action mapping using ForwardAction as follows:

      <action path=”/GotoSuccess” type=”org.apache.struts.actions.ForwardAction” parameter=”/Success.jsp” validate=”false” />

      Now, you have now addressed the duplicate submission due to accidental refreshing by the customer Problem : It does not prevent you from intentionally going back in the browser history and submitting the form again. Malicious users might attempt this if the form submissions benefit them or adversely impact the server.

    2. Synchronizer Token :

      Struts provide a token system which help solving this problem. Steps of implementation :

      1. add follwing line in the first(the page containing form you like to prevent from duplication) page or servlet,

      2. <% String token = TokenProcessor.getInstance().generateToken(request); session.setAttribute("org.apache.struts.action.TOKEN"
        , token); %>
      3. make a hidden field in the form as follow,

      4. <input type="hidden"
        name="<%=.TOKEN_KEY%>"
        value="<%=token%>"/>

      5. Now in the Action class you created, change code as follow,

      6. .... if(isTokenValid(request)){
        // your code if form submitted first time
        } else {
        // your code if form is duplicate.
        }
        saveToken(request);
        .....

No comments: