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

The Image-Based CAPTCHA: Part 2

, 1 Jul 2007
Rate this:
Please Sign up or sign in to vote.
The article continues the topic of image-based CAPTCHAs.

Background

The article continues the topic of image-based CAPTCHAs that was started in my previous article, The Image-Based CAPTCHA. Please look through it in order to get some idea about this article's subject.

Image-Based Bot Detector

I made a control - I named it ImageBasedBotDetector - that implemented the idea stated in the previous article. Its code differs from the example posted before, basically because of the separation of the code that renders the control and the code that renders the CAPTCHA image (it is replaced with an HttpHandler). For use, it needs to set TemplateImageFolder to a path where template images are located, and add the registration of the HttpHandler in the web.config.

<httpHandlers>
  <add verb="GET" path="ImageBasedBotDetector.ashx" 
       type="Marss.Web.UI.Controls.ImageBasedBotDetector, Marss.Web"/>
</httpHandlers>

ImageBasedBotDetector can be used as either a finished control, or as a base control if you want to add your own functionality - the GetTemplateImage and DrawCustom methods are virtual and can be overridden. An example of use you can be found in the demo project #1.

A few answers on your comments

After the previous article publication, I got many comments concerning the reliability of this type of CAPTCHAs. I'll try to systematize and answer them.

  1. It is possible to make a system that can recognize images and find the distorted part.
  2. Quite possible, no doubt. If it is possible to distinguish between a real person and a fake one on a photo, then it can be done for specific distortions on a picture. Most of the text-based CAPTCHAs are also crackable in 90-99% of the cases, but it does not prevent their general use. The fact is that there is no system that can crack everything; a specific implementation is required in every concrete case. Specific implementations mean resources and money. So, don't worry if your site is not as popular as Yahoo! or Google.

  3. A solution that relies on JavaScript is not firm because the script can be disabled.
  4. Sure, this is applicable for about 4% of visitors. But, it is hard to imagine a present-day web application that offers site-to-visitor interaction and does not use JavaScript. Besides, if you use ASP.NET controls, then most probably you already have these visitors excluded.

  5. Insufficient accessibility.
  6. The control now offers three types of distortion: Stretched, Random, and Volute (see picture).

    Stretched

    Volute

    Random

    Also, you can implement your own distortion if you set DistortionType to Custom and override the DrawCustom method.

  7. Possibility to download template images and compare them to an image that is generated by the CAPTCHA.
  8. To avoid pixel-to-pixel comparison, an original image is slightly distorted too. As for more complicated comparisons, read paragraph #1.

    Besides, a reconstruction of template images set can be avoided if you don't use any images set. It sounds strange, but actually it is rather simple. The basic principle is that though images of specific themes are required, there is no need to sort them manually. So you can use a search engine, for example Google Images search. Select a theme, for example, "Landscape", and choose the appropriate search keywords. Then, override the GetTemplateImage method.

    public class AdvancedImageBasedBotDetector : 
                 Marss.Web.UI.Controls.ImageBasedBotDetector
    {
      //search request pattern
    
      private const string requestPattern = 
        "http://images.google.com/images?hl=en&q=" + 
        "{0}&gbv=2&svnum=10&start={1}&sa=N&ndsp=20";
    
      protected override System.Drawing.Image GetTemplateImage()
      {
        //search keywords 
    
        string[] keywords = new string[] { "forest", "mountains", "waterfall", 
                                           "falls", "hills", "lake"};
        
        Random r = new Random();
        
        //build request url based on keyword that was selected in a random way
    
        string url = string.Format(requestPattern, 
                            keywords[r.Next(0, keywords.Length)], r.Next(0, 50));
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
        using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
        {
            if (resp.StatusCode == HttpStatusCode.OK)
            {
                string html;
                using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
                {
                    //get content of the search results page
    
                    html = sr.ReadToEnd();
    
                    resp.Close();
                    sr.Close();
                }
    
                Regex re = new Regex(@"dyn\.Img[(](?:""([^""]*)""[,)])*", 
                                     RegexOptions.Multiline);
                MatchCollection matches = re.Matches(html);
                if (matches.Count > 0)
                {
                    //select one of the image urls found on the search results page
    
                    Match match = matches[r.Next(0, matches.Count)];
                    string imageUrl = string.Format("{0}?q=tbn:{1}{2}",
                                            match.Groups[1].Captures[14],
                                            match.Groups[1].Captures[2],
                                            match.Groups[1].Captures[3]);
    
                    //get image
    
                    HttpWebRequest req2 = (HttpWebRequest)WebRequest.Create(imageUrl);
                    using (HttpWebResponse resp2 = (HttpWebResponse)req2.GetResponse())
                    {
                        if (resp2.StatusCode == HttpStatusCode.OK)
                        {
                            System.Drawing.Image im = 
                                System.Drawing.Image.FromStream(resp2.GetResponseStream());
                            resp2.Close();
                            return im;
                        }
                    }
                }
            }
        }
        //use default implementation if getting template image failed for any reason
    
        return base.GetTemplateImage();
      }
    }

    A working example can be seen in the demo project #2 or on my site.

  9. What is this necessary for?
  10. If the answer "pleasant variety" does not suit you, then - I guess - it may to say that this type of CAPTCHAs are more user friendly (one mouse click vs. typing 5-6 letters).

That is all. Start to criticize Smile | :) .

Other Links

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

About the Author

Mykola Tarasyuk
Software Developer (Senior)
Ukraine Ukraine
I am a software developer from Ukraine. In my spare time (this means "very rarely last years"), I am blogging about ASP.Net and web development.


Comments and Discussions

 
GeneralToo crackable Pinmemberreinux2-Jul-07 11:01 
GeneralRe: Too crackable PinmemberMykola Tarasyuk2-Jul-07 22:10 

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.140709.1 | Last Updated 1 Jul 2007
Article Copyright 2007 by Mykola Tarasyuk
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid