Using reCAPTCHA with FormMail

Important: Version 1.0 of the reCAPTCHA API is no longer supported, please upgrade to Version 2.0. Learn more

Here we will explain how to add reCAPTCHA to your FormMail script without using the reCAPTCHA Perl Module. If you know what you're doing, you can alternatively use the reCAPTCHA Perl Module.

Client Side (How to make the CAPTCHA image show up)

In your HTML page, inside the <form> element you must add the following code:

  <script type="text/javascript"
    src="http://www.google.com/recaptcha/api/challenge?k=your_public_key">
  </script>
  <noscript>
    <iframe src="http://www.google.com/recaptcha/api/noscript?k=your_public_key"
        height="300" width="500" frameborder="0"></iframe>

    <textarea name="recaptcha_challenge_field" rows="3" cols="40">
    </textarea>
    <input type="hidden" name="recaptcha_response_field"
        value="manual_challenge">
  </noscript>

It probably goes without saying, but we'll say it anyway: you need to replace the two instances of your_public_key with the public key that you received during the account creation process. Be careful that you don't use your private key by mistake.

This will basically add two parameters, which are passed to formmail.cgi (or FormMail.pl) through a POST request, namely:

  • recaptcha_challenge_field: This is the challenge created through your public key.
  • recaptcha_response_field: This is the user-submitted response to the challenge above.
  • Server Side (How to test if the user entered the right answer)

    Next, you need to modify formmail.cgi (or FormMail.pl) to handle the two parameters and to validate the challenge from the reCAPTCHA servers. At this point, it's probably a good idea to make a backup copy of your FormMail.pl, just in case. In the code below, "+" means the line needs to be added to the FormMail script, and "-" means the line needs to be removed from it. In every case, we show where the lines need to be added or removed by showing the adjacent lines in the FormMail script.

    First, you need to tell Perl to use the module LWP::UserAgent by adding the following line to FormMail:

     # ACCESS CONTROL FIX: Peter D. Thompson Yezek                                #
     #                     http://www.securityfocus.com/archive/1/62033           #
     ##############################################################################
     +use LWP::UserAgent;
     +
    

    (This will require the module LWP::UserAgent to be in your Perl environment. Most installations of Perl already have this module. In case the module is not installed, here are some basic instructions on installing Perl modules.)

    Then, add code to call the CAPTCHA check functionality defined below.

     # Check Required Fields
     &check_required;
    
     +# Check the captcha challenge and response.
     +&check_captcha;
     +
     # Send E-Mail
     &send_mail;
    
     # Return HTML Page or Redirect User
     &return_html;
    

    Now, validate the CAPTCHA response and generate an error if the response doesn't match the challenge.

     +##############################################################################
     +# Check the CAPTCHA response via the reCAPTCHA service.
     +sub check_captcha {
     +
     +      my $ua = LWP::UserAgent->new();
     +      my $result=$ua->post(
     +      'https://www.google.com/recaptcha/api/verify',
     +      {
     +          privatekey => 'your_private_key',
     +          remoteip   => $ENV{'REMOTE_ADDR'},
     +          challenge  => $Form{'recaptcha_challenge_field'},
     +          response   => $Form{'recaptcha_response_field'}
     +      });
     +
     +      if ( $result->is_success && $result->content =~ /^true/) {
     +              return;
     +      } else {
     +              &error('captcha_failed');
     +      }
     +}
     +
     # NOTE rev1.91: This function is no longer intended to stop abuse, that      #
     #    functionality is now embedded in the checks made on @recipients and the #
     #    recipient form field.                                                   #
    

    Finally, create the functionality that prints the error message in case the check fails:

             if ($Config{'missing_fields_redirect'}) {
                 print "Location: " . &clean_html($Config{'missing_fields_redirect'}) . "\n\n";
             }
     +    }
     +    elsif ($error eq 'captcha_failed') {
     +            print <<"(END ERROR HTML)";
     +Content-type: text/html
     +
     +<html>
     + <head>
     +  <title>Error: Captcha Check Failed</title>
     + </head>
     + <body bgcolor=#FFFFFF text=#000000>
     + <center>
     +  <table border=0 width=600 bgcolor=#9C9C9C>
     +    <tr><th><font size=+2>Error: Captcha Check Failed</font></th></tr%gt;
     +   </table>
     +  <table border=0 width=600 bgcolor=#CFCFCF>
     +    <tr><td>The Captcha response of the form you submitted did not match the challenge.
     +     Please check the form and make sure that your response matches the challenge in the captcha image.
     +     You can use the browser back button to return to the form.
     +     </center%gt;
     +    </td></tr>
     +   </table>
     +  </center>
     + </body>
     +</html>
     +(END ERROR HTML)
     +    }
             else {
                  foreach $missing_field (@error_fields) {
                      $missing_field_list .= "<li>" . &clean_html($missing_field) . "\n";
     .
     .
     .
      </html>
     (END ERROR HTML)
             }
     -    }
     -
         exit;
     }
    

    That's it! reCAPTCHA should now be working on your site.

    Further Reading

  • Customizing Look and Feel
  • Tips and Guidelines
  • Troubleshooting