Secure coding

PHP lab: PHP double submit problem.

Srinivas
August 14, 2017 by
Srinivas

If a user refreshes a page after submitting a form, he may accidentally post the content again resulting in duplicate submission, thus causing undesired results. This is known as double submit problem.

In this lab, we will programmatically understand why this problem occurs and how to fix this.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

Lets begin

The application is accessible from Kali Linux using the following URL.

http://192.168.56.101/webapps/double_submit/1/double_submit.html/

This looks the image below when accessed from a web browser.

Let us enter 1234 as user input and click Place Order to complete the order.

As you can see in the figure below, the order has been placed, and the entry has been added to the database.

Note: Just to understand the problem better, we are displaying the time from the server.

Now, let us click the refresh button and see what happens.

As we can see in the above figure, the request is ready to be sent again. If we click Resend, the form data (order) will be resubmitted resulting in a duplicate order.

We can check it by clicking Resend button.

If we compare the time in both the screenshots, they are different, and that confirms that the form has been resubmitted.

The following is an image of the same problem.

Lets check our code to see what's happening behind the scenes.

double_submit.html

<!DOCTYPE html>

<html>

<head>

</head>

<body>

<form action="process.php" method="post">

<h1>Submit your credit card details</h1>

<label for="Credit_Card">Credit Card number</label>

<input type="text" name="credit_card"/>

<br /><br />

<input type="submit" value="Place Order"/>

</form>

</body>

</html>

As we can see in the excerpt above, the double_submit.html page sends user entered data to process.php as a post request.

Now, let us see what process.php does with the data received.

process.php

<?php

$cardnumber = $_POST['credit_card'];

$db_file = dirname(__FILE__) . '/db.txt';

file_put_contents($db_file, 'cardnumber '.$cardnumber . ' time '.date('H:i:s'));

$data = file_get_contents($db_file);

?>

<!DOCTYPE html>

<html>

<head>

<title> Submitted Sucessfully </title>

</head>

<body>

<H1> Submitted Successfully</H1>

<h2>Data written into the database: <?php echo $data ?></h2>

</body>

</html>

process.php is taking the user entered data and it is saving it to a file named db.txt on the server and then it sends 200 OK response to the client. If this process.php page is refreshed, it resubmits the post data it was holding from the previous request.

 

How to avoid this?

This is a well-known problem and the PRG (POST/REDIRECT/GET) Pattern is used to avoid this. It basically instructs our process.php page to issue a redirect another page instead of sending 200 OK response to the client.

Let us see how we can achieve this.

process.php

<?php

$cardnumber = $_POST['credit_card'];

$db_file = dirname(__FILE__) . '/db.txt';

file_put_contents($db_file, 'cardnumber '.$cardnumber . ' time '.date('H:i:s'));

header('HTTP/1.1 301 Moved Permanently');

header('Location: success.php');

die();

?>

As you can see in the excerpt above, process.php is redirecting the user to success.php after inserting the data.

success.php

<?php

$db_file = dirname(__FILE__) . '/db.txt';

$data = file_get_contents($db_file);

?>

<!DOCTYPE html>

<html>

<head>

<title> Submitted Sucessfully </title>

</head>

<body>

<H1> Submitted Successfully</H1>

<h2>Data written into the database: <?php echo $data ?></h2>

</body>

</html>

success.php will read the contents from the back end and displays them over a GET request.

Let us verify this using the updated code.

The modified application can be accessed from the following URL.

http://192.168.56.101/webapps/double_submit/2/double_submit.html/

Enter the credit card number and click Place Order.

As you can see in the figure above, the order is placed. Now, even if we refresh the page, we will not see any duplicate insertion because we are on success.php and it only makes a GET request to fetch and display data from the backend storage.

Learn Secure Coding

Learn Secure Coding

Build your secure coding skills in C/C++, iOS, Java, .NET, Node.js, PHP and other languages.

Image Credits

https://upload.wikimedia.org/wikipedia/commons/f/f3/PostRedirectGet_DoubleSubmitProblem.png

Srinivas
Srinivas

Srinivas is an Information Security professional with 4 years of industry experience in Web, Mobile and Infrastructure Penetration Testing. He is currently a security researcher at Infosec Institute Inc. He holds Offensive Security Certified Professional(OSCP) Certification. He blogs atwww.androidpentesting.com. Email: srini0x00@gmail.com