Click here to Skip to main content
Click here to Skip to main content

Custom reCaptcha Validation

By , 7 Oct 2010
 

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://api.recaptcha.net/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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Nathan Staudt
Web Developer
United Kingdom United Kingdom
Member
I've been a web application developer since the late 1990s, working for eCommerce, media and telecoms companies across europe and america.
 
I have a BSc (Hons) in computing from Middlesex University and took a few MCP exams several years ago too.
 
Born in America, I grew up in Ireland. My father encouraged my interest in computers as a child when he would bring home his "portable" ibm pc... (20kg or something like that) and I first wrote some stuff in QBasic aged seven or eight, but my real interest in computers took off when my family got internet access at home in the early 90s.
 
Feel free to email me Smile | :)

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionEnglish language audio challengememberdacku8716 Feb '11 - 22:42 
GeneralMy vote of 3memberAndrey Mazoulnitsyn26 Jan '11 - 21:30 
NewsWhere I used this codememberNathan Staudt8 Oct '10 - 3:03 
QuestionGood stuffmemberSike Mullivan7 Oct '10 - 3:58 
AnswerRe: Good stuffmemberSike Mullivan7 Oct '10 - 4:05 
GeneralRe: Good stuffmemberNathan Staudt7 Oct '10 - 4:12 
GeneralRe: Good stuffmemberSike Mullivan7 Oct '10 - 4:23 
GeneralRe: Good stuffmembershakil03040037 Oct '10 - 4:36 
GeneralRe: Good stuffmemberNathan Staudt7 Oct '10 - 4:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 7 Oct 2010
Article Copyright 2010 by Nathan Staudt
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid