Handling Online Payments Part 7 - Preventing Automated Form Submissions
04-06-201107:32 AM - edited 10-20-201109:57 AM
This is part seven of a multi-part series on handling online payments.
In Part 1 of this series we identified our goals (creating a payment form that was usable, accessible, and secure) and began by creating the form we will use to capture payment information. In Part 2 of this series we continued this process by exploring how we will handle the data submitted by that form. In Part 3 of this series we took the data received and sanitized in Part 2 and validated that it was in a format we required. In Part 4 of this series we took the errors we found in Part 3 and displayed them in a user-friendly format to minimize cart abandonment. In Part 5 of this series we processed the payment and handled the response returned to us whether it be approved, declined, or an error completing the transaction process.
In Part 6 of this series we changed our focus to improving upon our form to make it more user-friendly, secure, and easier to maintain. We accomplished this by preventing duplicate form submissions using the POST/REDIRECT/GET design pattern. We will continue along this path and see how we can prevent spambots and other malware from making automated form submissions.
Any webmaster who has run a website for long enough will know about the frustration of dealing with spambots submitting forms on their website. This can cause problems with unwanted data, spam, and even sophistication attacks that can compromise your website. In our case it can result in unwanted payments being made possibly with stolen credit cards. The potential chargebacks alone could put a company out of business.
Fortunately as web developers we have options for preventing these submissions from occurring. "Prevention" being the key word as we want to stop the submissions before payment can be made. There are several methods we can implement to accomplish this for us and we will focus on using two of them. They are:
According to Wikipedia "in computer terminology, a honeypot is a trap set to detect, deflect, or in some manner counteract attempts at unauthorized use of information systems." For our form, the honeypot will be a fake form field that only bots can see. The reason for this is automated bots will often attempt to complete every form field they can find in the HTML of your form. This includes fields that are hidden from view from normal users. So if this field has a value when the form is submitted we can assume it was submitted by a bot and produce and error message. Bots will not be able to understand or respond to the error and will be prevented from succeeding.
Let's see how we would do this in our form. We will start by adding the hidden form field.
Now that we have our form field in place we need to hide it with CSS. That's very easy to do with this code:
/* hp stands for HoneyPot */
display: none !important;
This CSS will hide our form field for us. We use !important to make sure that this rule takes precedence over any other rule that may accidentally display it to the user.
Our last step is to add a check in our PHP code to look for this form field and, if there is a value submitted, generate an error.
$honeypot = sanitize($_POST['ssn']);
$errors['hp'] = "This form submission is invalid. Please try again or contact support for additional assistance.";
In this code we read in the value of the honeypot field and check to see if it has a value. If it does we generate an error. We make sure the error is human friendly just in case a user somehow manages to submit a value for this field by accident. But if a bot sees it they'll be stick and their attempt to abuse our form will be thwarted.
A form token provides protection against forms of attacks against your site by placing a unique random token as a hidden field that can only be used once. If the form is submitted without a token, or the wrong token, an error is generated. For this to work we need to place the token in the form as a hidden field and then store its value on the server so we know what value to expect when the form is submitted. We will start by looking at the code that generates the token for us. We will place it after our PHP code for handling form submissions but before our HTML.
$_SESSION['token'] = md5(uniqid(rand(), true));
Generating the token is easy to do as we take a random string and hash it using the MD5 algorithm. The result will be a random 32 character string. We place it in a $_SESSION variable so its value is stored across page requests and we can access it after the form is submitted.
Now we need to place this token in our form as a hidden field so users won't see it but it will be included in their form submission.
Now that we have the token in place we need to have our PHP code verify the correct token was submitted.
$token = sanitize($_POST['token']);
if ($token !== $_SESSION['token'])
$errors['token'] = "This form submission is invalid. Please try again or contact support for additional assistance.";
An additional advantage of the form token is it also protects against Cross Site Request Forgery attacks (CSRF). These attacks are when a user attempts to mimic a legitimate user by hijacking their browsing session and submit the form as that user. Using form tokens makes it extremely difficult for the attacker to submit the form with the proper token making their chances for success very, very small. (I suggest reading more on CSRF attacks as they are a legitimate danger for any website that accepts credit card information).
Updated Payment Form
To see our new form with the honeypot and form token included just download the attachment at the end of this blog post.