Click here to Skip to main content
15,881,709 members
Articles / Programming Languages / C#

Silverlight Captcha Example

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
1 Sep 2009CPOL5 min read 33.1K   466   27   4
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.

C#
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:

XML
<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:

XML
<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:

JavaScript
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

This article was originally posted at http://feeds2.feedburner.com/CSharperImage

License

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


Written By
Program Manager Microsoft
United States United States
Note: articles posted here are independently written and do not represent endorsements nor reflect the views of my employer.

I am a Program Manager for .NET Data at Microsoft. I have been building enterprise software with a focus on line of business web applications for more than two decades. I'm the author of several (now historical) technical books including Designing Silverlight Business Applications and Programming the Windows Runtime by Example. I use the Silverlight book everyday! It props up my monitor to the correct ergonomic height. I have delivered hundreds of technical presentations in dozens of countries around the world and love mentoring other developers. I am co-host of the Microsoft Channel 9 "On .NET" show. In my free time, I maintain a 95% plant-based diet, exercise regularly, hike in the Cascades and thrash Beat Saber levels.

I was diagnosed with young onset Parkinson's Disease in February of 2020. I maintain a blog about my personal journey with the disease at https://strengthwithparkinsons.com/.


Comments and Discussions

 
GeneralMy vote of 5 Pin
mbcrump13-Aug-11 13:03
mentormbcrump13-Aug-11 13:03 
GeneralMy Vote 5 Pin
Kunal Chowdhury «IN»27-Feb-10 8:05
professionalKunal Chowdhury «IN»27-Feb-10 8:05 
QuestionWhy using Silverlight only for Captcha? Pin
Michael Epner8-Sep-09 3:37
Michael Epner8-Sep-09 3:37 
AnswerRe: Why using Silverlight only for Captcha? Pin
Jeremy Likness8-Sep-09 3:39
professionalJeremy Likness8-Sep-09 3:39 

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

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