ドキュメント

Tutorials:Safer Contact Forms Without CAPTCHAs

From jQuery JavaScript Library

Jump to: navigation, search

Building a complete, jQuery-based, solution for stopping spammers from mis-using your forms.

Original: http://15daysofjquery.com/safer-contact-forms-without-captchas/11/
Author: Jack Born

Similar Tutorials: AjaxManipulationForms

Here’s a subject that’s close to my heart: secure contact forms.

As I mentioned in a previous tutorial, one common use of contact forms is to help visitors communicate with you without exposing your email address to the email harvesting software used by spammers.

But when it comes to spam, hardly anything is worse than an insecure contact form. Imagine getting a nasty note from your web hosting company that your site has been used to send out massive amounts of email about black market erection medication and, oh by the way, your site is offline until you get it fixed - thank you very much.

So what I’m going to show you today is a simple method for adding an extra layer of security to ANY contact form on your site.

Contents

The Situation

You notice that spammers have been remotely probing your contact forms for vulnerabilities… and you want them to quit.

The Problem

You don’t want to use CAPTCHA’s (Completely Automated Public Turing Test to Tell Computers and Humans Apart) because you just know that requiring your visitors to read squiggly letters and numbers just to send you a message is going to suppress communication - not encourage it.

An example CAPTCHA

Bottom line: you want to make life tough for the Bad Guys and super simple for the Good Guys.

The Solution

You’re going to use jQuery to add some hidden tag information to the contact form when the page loads. When the form is sent to the processor, you’ll use some simple PHP code to verify the following:

  • The hidden tag is present
  • The hidden tag’s value matches a ‘token’ stored as a cookie by your visitor’s browser
  • The timestamp for the hidden tag hasn’t expired

In other words, your visitor will have a limited amount of time (specified by you) to fill in the form and send it. And if a spammer tries to post information to your form processor remotely they’re going to hit a big fat roadblock. Do not pass go, do not collect $200.

What I’m going to share with you is a modified concept I read from a very smart fellow named Chris Shiflett. He’s a security expert on all sorts of issues that PHP programmers can come across if they’re not careful.

The Tutorial

I got great responses from the tutorial for Table Striping Made Easy so I’ve decided to do another “walk through” tutorial with screen grabs. It’s a little time consuming, but hey, you’re worth it.

The Idea

  • Make it difficult for spammers to probe our forms for weakness
  • Keep it easy for the "good guys" to use our contact forms
    • Therefore we need to avoid CAPTCHA's
    • There's research that indicates that they're not as effective as once thought
    • We'll borrow some concepts from Chris Shiflett, PHP security expert, and improve on them

Specifically...

  • When the contact form is loaded we'll make an AJAX call to a PHP file
  • The PHP file will grab the current time (according to the server, not the visitor's browser)
  • The PHP file will combine the timestamp, plus a secret word, and generate a 32 character 'hash' and store it as a cookie on the visitor's browser
  • jQuery will receive the timestamp information from the AJAX call and store the hash or 'token' timestamp as a hidden form tag
  • When the form is sent for processing, the value of the timestamp will be compared to the 32 character 'token' stored in the cookie
  • If the information doesn't match, or is missing, or if the timestamp is too old, we'll kill execution of the form processor and a spammer looking for easy prey will move on to another target

So let's get rolling... first we need a contact form.

Simple Contact Form:

Image:Form2.png
Next... bring on the jQuery

Grab the jQuery Library

Image:Form3.png
And kick start the rest of the code with $('document').ready()
Image:Form4.png
Next... remove the "javascript required" warning

Consider If Your Visitor Isn't Using JavaScript

  • One method is to put a warning at the top of the form
  • Give the P tag a class name or id
    Image:Form5b.png
  • Use jQuery to remove() the P element containing the "JavaScript required" message
    Image:Form5.png
  • If the visitor has JavaScript off - they will see the warning message

PHP File

  • 'token.php' is used to perform four actions:
    • Grab the current server time using mktime()
    • Combine the server time with a secret word you supply and create a 'hash' using the md5() function
    • Store the hash or 'token' value in a cookie
    • Send the server time back to jQuery so it can be inserted into the form html on the client side

Image:Form7.png

  • Using the server time (via PHP) instead of a JavaScript call to the current browser time is more reliable
    • Helps us determine how long the visitor took to complete the form
  • Makes it much more difficult for an outsider to "monkey" with our token function

Ajax Call

Our JavaScript will use jQuery's $.get(file, callbackFunction) for the Ajax call. This will do a simple GET request to the server to retrieve the text.

Image:Form8.png

jQuery Appends the Server Time

Use append() to tell jQuery to add a hidden input to the form just before the closing form tag.

Image:Form9.png
Image:Form10.png
Image:Form11.png

Checking the Form

test.php is the example PHP code used to verify the token

  • Is the token present?
  • Does it match the timestamp when run through the md5() function?
  • Has too much time elapsed?

Image:Form12.png

Prevent Caching

  • Internet Explorer has a nasty habit of caching the token.php file
  • We want this file run every time the contact form is loaded
  • So after the cookie is sent, we're going to send some special headers

Image:Form13.png

What makes this solution better?

Chris Shiflett's code required that the contact form page be written in PHP

  • My jQuery adaptation of his code makes it possible to use this solution on any contact form
  • No need to change .htm extension to .php
  • Could be used on a blog where adding php code to a contact form plugin would require extensive hacking

What makes this solution worse?

  • Chris Shiflett's code required only that cookie be enabled on a visitor's machine
  • My jQuery adaptation requires cookies and JavaScript
    • Is this really a huge issue - IMO: "no"
      • It's a trade-off that you, the designer/programmer, must evaluate

Final Analysis

  • Pro: Easy to use on any contact form
  • Con: a teeny tiny percentage of your audience will either have javascript or cookies disabled
    • You just have to weigh this against your alternatives:
      • Less security for your forms + spammers probing for weak points
      • Annoying CAPTCHA tests that suppress communication with visitors

Demo and Code

Silver Bullet?

“So now my forms are 100% secure and I can use Generic Free Contact Form Processor With Sloppy Code and feel safe?”

Uh… no.

This security concept is based on a key assumption:

Spammers would prefer to go after the “low hanging fruit” than spend all day trying to crack a tricky contact form.

Now listen carefully, dear friend:

This technique, although strong, is not a cure for a weak form processor.

My attitude towards securing a contact form is to use multiple methods on both the server side and the client side so that a spammer is going to have to invest an enormous amount of resources to even come close to succeeding with their evil plot.

I view the client side protection as analogous to posting a sticker on the windows of a home to indicate that the house is wired with an alarm. Thieves know to look for stickers, dogs in the yard, lights on the exterior of a home, and other signs of a well guarded house. They’re looking for high payoff with minimal work and risk.

In other words, if you can thwart 99% of attacks before they really get started and you can do it so easily why wouldn’t you? That’s what this technique does.

But it’s not a silver bullet cure for a crappy form processor.