Click here to Skip to main content
Click here to Skip to main content
Go to top

Silverlight Captcha Example

, 1 Sep 2009
Rate this:
Please Sign up or sign in to vote.
Silverlight, with its powerful text and graphics manipulation capabilities and strong interaction with the scripting DOM, seems to be the perfect engine for a Captcha challenge.

Silverlight, with its powerful text and graphics manipulation capabilities and strong interaction with the scripting DOM, seems to be the perfect engine for a Captcha challenge.

Captcha is a challenge-response test used to determine to a degree of confidence that the end user is really human and not a bot. You see Captcha on things like forums, sign up forms, comment posts, and other places that may be susceptible to attacks by scripted bots. Usually, a Captcha involves playing a sound or displaying a distorted image that humans should be able to recognize but would be extremely hard for pattern-matching and/or optical character recognition (OCR) technology to decipher. Because the test is issued by a computer to test for a human, it is often referred to as a reverse-Turing test (a Turing test is designed by humans to test computers).

The key to Captcha is that it makes it difficult, if not impossible, for scripted software to determine the answer to the challenge. Asirra is an example of a Captcha challenge that displays random images of cats and dogs. The user is asked to identify only the cats by clicking on them. While easy for humans, this test is extremely difficult for computer algorithms.

As I was coding the other day, it occurred to me that Silverlight would be perfect for issuing Captcha challenges. It is very easy and straightforward to manipulate text and graphics to obscure the image, and furthermore, the output is NOT a simple bitmap that a robot could parse. Instead, it is an interactive plugin so for a script to recognize the image, it would have to have its own Silverlight engine and be able to scan and recognize what Silverlight renders.

I set out to produce a working example. I purposefully kept to the basics so those of you reading this who are interested have the opportunity to extend and add features.

The first step was to create a simple Captcha challenge class to use.

namespace SilverCaptcha.MVVM
{
    [ScriptableType]
    public class CaptchaViewModel
    {
        private const string CAPTCHA_KEY = "SilverCaptcha";

        private static readonly char[] _charArray = 
		"ABCEFGHJKLMNPRSTUVWXYZ2346789".ToCharArray();

        public string CaptchaText { get; set; }

        public CaptchaViewModel()
        {
            char[] captcha = new char[8];

            Random random = new Random();

            for (int x = 0; x < captcha.Length; x++)
            {
                captcha[x] = _charArray[random.Next(_charArray.Length)];
            }

            CaptchaText = new string(captcha);

            HtmlPage.RegisterScriptableObject(CAPTCHA_KEY, this);
        }

        [ScriptableMember]
        public bool IsHuman(string challengeResponse)
        {
            return challengeResponse.Trim().ToUpper().Equals(CaptchaText);
        }
    }
}

The class simply generates a random 8-digit sequence of characters. We supply a list of allowed values to avoid some of the common characters like the number one and letter "I" that could be easily mistaken for one or the other. The property CaptchaText exposes this value. The IsHuman method is decorated with the ScriptableMember tag. This makes it available to the HTML DOM so that you can call it directly from JavaScript. To call it, you must register a "key" or handle to the object. This is done in the constructor through the RegisterScriptableObject call. We are giving it a handle in the JavaScript DOM of "SilverCaptcha." We'll see later how this is used.

Points of Extension

  • Add a method to "refresh" the challenge, i.e. generate a new one (hint: to do this, you'll also need to implement INotifyPropertyChanged)
  • Add parameters to control the challenge (length, use of alpha or numeric, etc.)

Next, we'll need to show the challenge. Because I chose to use the Model-View-ViewModel pattern (MVVM), we won't need any code behind for the XAML. Instead, everything will be bound in the XAML itself. The XAML I came up with looks like this:

<UserControl x:Class="SilverCaptcha.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:MVVM="clr-namespace:SilverCaptcha.MVVM">
    <UserControl.Resources>
        <MVVM:CaptchaViewModel x:Key="CaptchaVM"/>
    </UserControl.Resources>    
    <Grid Width="100" Height="25" Margin="2" DataContext="{StaticResource CaptchaVM}">
        <Grid.Background>
            <LinearGradientBrush x:Name="CaptchaBackground" 
			EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="LightBlue" Offset="1" />
                <GradientStop Color="LightSalmon" />
            </LinearGradientBrush>
        </Grid.Background>
        <TextBlock FontSize="14" Width="Auto" Height="Auto" 
                   HorizontalAlignment="Center" VerticalAlignment="Center" 
                   Text="{Binding CaptchaText}"
                   RenderTransformOrigin="0.5,0.5"> 
            <TextBlock.RenderTransform>
               <RotateTransform Angle="-5"/>              
            </TextBlock.RenderTransform>
            <TextBlock.Foreground>
                <LinearGradientBrush EndPoint="0.5,0" 
                    StartPoint="0.5,1">
                    <GradientStop Color="Black" Offset="1" />
                <GradientStop Color="Gray" />
                </LinearGradientBrush>
                                    
            </TextBlock.Foreground>
        </TextBlock>
    </Grid>
</UserControl>

This is fairly straightforward. By referring to CaptchaViewModel in the resources, an instance is created that can then be referenced using the key. I bind the class to the data context of the main grid using {StaticResource CaptchaVM}. The gradient is used to obscure the image somewhat. Because the class itself is bound to the grid, we can now simply bind the CaptchaText property to the text block. We also give that a slight gradient to make it more confusing to image scanning software, then rotate it against the background. That's all there is to it!

Points of Extension

  • Obviously, you could randomize or parameterize the angle of rotation and other attributes of the text
  • A more severe grid may help obscure the challenge but may also make it more difficult for human readers
  • Add a refresh button or icon to refresh the challenge for the user

Now, let's use it in a page. The page itself is fairly straightforward: we have a form with a table, and inside the table is a reference to the Silverlight XAP file, a text box for users to enter their response to the challenge, and a button to click. This section looks like this:

<form id="_form1" runat="server" style="height:100%">
    <table><tr><td align="center">
    <div id="silverlightControlHost">
        <object id="silverlightControl" data="data:application/x-silverlight-2," 
		type="application/x-silverlight-2" width="110" height="30">
        ... etc, etc ...
     </object></div></td></tr><tr>
     <td align="center">Enter The Text You See Above:<br />
	<input type="text" maxlength="20" id="txtChallenge" /></td></tr><tr>
     <td align="center"><input type="button" onclick="validateCaptcha();
	return false;" value=" OK "/></td></tr></table>
    </form>

(Click here to see a live example.)

The key here is that we've assigned the Silverlight object an identifier of silverlightControl. If you use the JavaScript or control method to load the Silverlight, either way you just need a way to point to the object in the DOM for the Silverlight control.

The JavaScript function is then very straightforward. We simply call the method we exposed in the Silverlight class that will compare the response to the challenge. That code looks like this:

function validateCaptcha() {
    var silverlightCtrl = document.getElementById("silverlightControl");
    var challenge = document.getElementById("txtChallenge").value;
    var valid = silverlightCtrl.Content.SilverCaptcha.IsHuman(challenge);
    alert(valid ? "You are human!" : "You don't appear to be human, try again!");
}

This is what the final product looks like:

captcha.png

As you can see, calling the Silverlight method is as simple as grabbing the control that hosts Silverlight, going into Content, then referencing the tag we gave it when we registered it in the Silverlight code. Then we simply call the method with the contents of the text box and it returns either true or false based on whether or not the response matches the challenge.

This is obviously a fast and basic example but it demonstrates just how flexible and powerful Silverlight can be to generate "mini-apps" or controls that you can embed in your existing HTML pages.

Jeremy Likness

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Jeremy Likness
Architect Wintellect
United States United States
Jeremy Likness is a principal consultant at Wintellect. Jeremy, an experienced entrepreneur and technology executive, has successfully helped ship commercial enterprise software for 20 years. He specializes in catalyzing growth, developing ideas and creating value through delivering software in technical enterprises. His roles as business owner, technology executive and hands-on developer provided unique opportunities to directly impact the bottom line of multiple businesses by helping them grow and increase their organizational capacity while improving operational efficiency. He has worked with several initially small companies like Manhattan Associates and AirWatch before they grew large and experienced their transition from good to great while helping direct vision and strategy to embrace changing technology and markets. Jeremy is capable of quickly adapting to new paradigms and helps technology teams endure change by providing strong leadership, working with team members “in the trenches” and mentoring them in the soft skills that are key for engineers to bridge the gap between business and technology.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermbcrump13-Aug-11 13:03 
GeneralMy Vote 5 PinmemberKunalChowdhury27-Feb-10 8:05 
QuestionWhy using Silverlight only for Captcha? PinmemberMichael Epner8-Sep-09 3:37 
AnswerRe: Why using Silverlight only for Captcha? PinmemberJeremy Likness8-Sep-09 3:39 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 1 Sep 2009
Article Copyright 2009 by Jeremy Likness
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid