Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Custom reCaptcha Validation

0.00/5 (No votes)
15 Nov 2013 1  
How to manually integrate reCaptcha into your site

Introduction

reCaptcha is a very useful Captcha tool to verify that a visitor to your site is indeed human. This is mainly useful for preventing spam.

Here's a sample reCaptcha:

a sample captcha

There are many custom Captcha solutions available on CodeProject, but reCaptcha has a number of advantages:

  • It's maintained by Google - so if the captcha images are compromised, an update from Google will resolve the problem without any work from the web developer.
  • Answers to reCAPTCHA challenges are used to digitize textual documents.
  • Your web server doesn't have to spend processor time producing captcha images.
  • reCaptcha has an audio option which is useful for visually impaired users.

These points are good, unless you're not a fan of Google.

Background

While working on a new feature for my website, I had some problems implementing reCaptcha.

There is a .NET server control provided, however, I couldn't get the client-side script to pick up the theme I wanted to use, so I decided to tough it out and implement it myself.

Using the Code

Note - reCaptcha requires you to create cryptographic keys. These are used to improve security and are easy to create - just click here to create your keys and then add your keys to the web.config of the demo.

First, we need to set up the client-side.

Include the reCaptcha client library in the header of your page:

<head>
    <script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js">
    </script>
</head>     

Next, add the following code:

<div id="recaptcha_div"></div>
<script type="text/javascript">
    Recaptcha.create("<%=Config.PublicKey %>",
        "recaptcha_div", {
        lang: "<%=LanguageCode %>",
        theme: "clean",
        callback: Recaptcha.focus_response_field
    });
</script>

As you can see, we're taking two values from the server and injecting them directly into the client:

  1. Config.PublicKey (This is your public reCaptcha key - if you don't have one, then head over here to get one.)
  2. LanguageCode

If you want to change the theme used by the captcha, you can read more here.

Next, the server-side code.

The article download includes the full server-side code, here I will just outline the important parts.

Add a custom validator to your page and provide the following code as its server validation method:

// our custom server validator's validation method
protected void OnRecaptchaValidate(object sender, ServerValidateEventArgs e)
{
    string challenge = Request.Form["recaptcha_challenge_field"];
    string clientResponse = Request.Form["recaptcha_response_field"];
    
    reCaptchaValidation validator = 
        new reCaptchaValidation(
                    Config.Proxy,       // if you don't require a proxy to access 
                // the internet, just comment out this line.
                    Request.UserHostAddress, 
                    Config.PrivateKey, 
                    challenge, 
                    clientResponse);
                    
    e.IsValid = validator.Validate();
    
    if (!e.IsValid)
    {
        if (validator.IsErrored)
        {
            // oh dear, something not right
            
            if (validator.Exception != null)        // an exception occurred while 
                        // trying to validate
                Outcome.Text = validator.Exception.ToString();
            else if (validator.ValidationResult != null)  // the validation web service 
                        // returned an error code 
                    // (other than an invalid captcha solution)
                Outcome.Text = "web service error: " + validator.ValidationResult;
        }
    }
}

The validation is wrapped in a class called reCaptchaValidation:

public class reCaptchaValidation
{
    private string challenge, response, privateKey, ip;
    private IWebProxy proxy;

    public reCaptchaValidation(string clientIP, string privateKey, 
    string challenge, string response) : this(null, clientIP, privateKey, 
    challenge, response) { }

    public reCaptchaValidation(IWebProxy proxy, string clientIP, 
        string privateKey, string challenge, string response)
    {
        this.proxy = proxy;
        this.ip = clientIP;
        this.privateKey = privateKey;
        this.challenge = challenge;
        this.response = response;
    }

    private bool _errored;
    public bool IsErrored
    {
        get
        {
            return _errored;
        }
    }

    private Exception _ex;
    public Exception Exception
    {
        get
        {
            return _ex;
        }
    }

    private string _vr;
    public string ValidationResult
    {
        get
        {
            return _vr;
        }
    }

    public bool Validate()
    {
        try
        {
            string post = "privatekey=" + HttpUtility.UrlEncode(privateKey) + 
        "&remoteip=" + HttpUtility.UrlEncode(ip) + "&challenge=" + 
        HttpUtility.UrlEncode(challenge) + "&response=" + 
        HttpUtility.UrlEncode(response);

            WebRequest wr = HttpWebRequest.Create
            ("http://www.google.com/recaptcha/api/verify");
            wr.Method = "POST";

            if (proxy != null)
                wr.Proxy = proxy;

            wr.ContentLength = post.Length;
            wr.ContentType = "application/x-www-form-urlencoded";
            using (StreamWriter sw = new StreamWriter(wr.GetRequestStream()))
            {
                sw.Write(post);
                sw.Close();
            }

            HttpWebResponse resp = (HttpWebResponse)wr.GetResponse();
            using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
            {
                string valid = sr.ReadLine();
                if (valid != null)
                {
                    if (valid.ToLower().Trim() == "false")
                    {
                        string errorcode = sr.ReadLine();

                        if (errorcode != null)
                        {
                            if (errorcode.ToLower().Trim() != "incorrect-captcha-sol")
                            {
                                _vr = errorcode;
                                _errored = true;
                                return false;
                            }
                        }
                    }

                    return (valid.ToLower().Trim() == "true");
                }
                else _vr = "empty web service response";

                sr.Close();
                return false;
            }
        }
        catch (Exception caught)
        {
            _errored = true;
            _ex = caught;
        }
        return false;
    }
}

This class handles the validation of the user's captcha response by posting all the required information to the Google recaptcha validation web service.

I've made the demo web application as simple to use as possible - just supply the required values in the web.config.

History

  • 7th October, 2010: Published.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here