<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Depth-First: Tag captchasdotnet</title>
    <link>http://depth-first.com/articles/tag/captchasdotnet</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Walking the Web of Chemical Informatics</description>
    <item>
      <title>Fighting Spam on the Cheap with CAPTCHA: A Simple Ruby Library for captchas.net</title>
      <description>&lt;p&gt;&lt;a href="http://flickr.com/photos/deadhorse/246252806/"&gt;&lt;img src="http://depth-first.com/demo/20070903/spam.jpg" align="right" border="0"&gt;&lt;/img&gt;&lt;/a&gt;A &lt;a href="http://depth-first.com/articles/2007/09/01/fighting-comment-spam-on-the-cheap-with-captcha"&gt;recent article&lt;/a&gt; discussed two free services for cheaply integrating &lt;a href="http://en.wikipedia.org/wiki/Captcha"&gt;CAPTCHAs&lt;/a&gt; into Web applications. One of these services, &lt;a href="http://captchas.net"&gt;captchas.net&lt;/a&gt;, apparently has no publicly-available Ruby library. Given the popularity of &lt;a href="http://rubyonrails.com"&gt;Ruby on Rails&lt;/a&gt; for building Web applications, and the increasing need for spam protection offered by services such as &lt;a href="http://captchas.net"&gt;captchas.net&lt;/a&gt;, it seems only logical that such a library should exist. This article, the first in a series, documents the first step in the development of a simple Rails library for working with captchas.net.&lt;/p&gt;

&lt;h4&gt;Got Key?&lt;/h4&gt;

&lt;p&gt;To use captchas.net, you'll need to &lt;a href="http://captchas.net/registration/"&gt;register for an account&lt;/a&gt;. You'll receive a secret key used in decoding the text represented in the CAPTCHA, and a username that will be encoded with your capthcas.net URLs.&lt;/p&gt;

&lt;h4&gt;Building a URL&lt;/h4&gt;

&lt;p&gt;To get your CAPTCHA image from captchas.net, construct a URL containing the appropriate parameters. The simplest form of a captchas.net URL accepts your user name ('demo') and a random phrase ('my_random_text'), and returns a complete CAPTCHA image. Customization is possible, but we'll just stick with the simple case for now. As an example, this URL:&lt;/p&gt;

&lt;div class="console"&gt;
&lt;pre&gt;
http://image.captchas.net/?client=demo&amp;random=my_random_text
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;generates this image:&lt;/p&gt;

&lt;p&gt;&lt;center&gt;&lt;a href="http://image.captchas.net/?client=demo&amp;amp;random=my_random_text"&gt;&lt;img src="http://image.captchas.net/?client=demo&amp;amp;random=my_random_text"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/center&gt;&lt;/p&gt;

&lt;p&gt;The URL above is all you need to embed a CAPTCHA into your webpage. The random text we've encoded in the URL ('my_random_text') is processed by the captchas.net server to create the six-character sequence shown in the image. Read on to find out how.&lt;/p&gt;

&lt;h4&gt;Decoding the CAPTCHA&lt;/h4&gt;

&lt;p&gt;We've got a CAPTCHA, but how do we know what's written in it? This is where our secret key comes in. Here's the method used by the captchas.net server to generate the image text:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;concatenate the secret key and the random string (example: 'secret' and 'my_random_text' become 'secretmy_random_text')&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if &lt;tt&gt;alphabet&lt;/tt&gt; or &lt;tt&gt;character_count&lt;/tt&gt; differs from 'abcdefghijklmnopqrstuvwxyz' and 6, respectively, append both separated by ':' (&amp;lt;secret&amp;gt;&amp;lt;random&amp;gt;:&amp;lt;&lt;tt&gt;alphabet&lt;/tt&gt;&amp;gt;:&amp;lt;&lt;tt&gt;character_count&lt;/tt&gt;&amp;gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;take the MD5-sum of the resulting string&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;take the first &lt;tt&gt;character_count&lt;/tt&gt; bytes of the resulting 16-byte-long MD5 value&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;determine the remainders of this &lt;tt&gt;character_count&lt;/tt&gt; bytes, when dividing by the length of &lt;tt&gt;alphabet&lt;/tt&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;every number encodes a character from the chosen &lt;tt&gt;alphabet&lt;/tt&gt; (example: "hnrppb")&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="http://catpchas.net"&gt;captchas.net site&lt;/a&gt; has a more complete description of the algorithm and an interactive CAPTCHA generator that is very helpful in understanding how CAPTCHAs are generated.&lt;/p&gt;

&lt;h4&gt;A Simple Library&lt;/h4&gt;

&lt;p&gt;Given the algorithm, a short Ruby library can be written to find the text encoded in a captchas.net CAPTCHA:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;digest/md5&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;Captcha&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;get_text&lt;/span&gt; &lt;span class="ident"&gt;secret&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;random&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;alphabet&lt;/span&gt;&lt;span class="punct"&gt;='&lt;/span&gt;&lt;span class="string"&gt;abcdefghijklmnopqrstuvwxyz&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;character_count&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;character_count&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="ident"&gt;character_count&lt;/span&gt; &lt;span class="punct"&gt;&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;16&lt;/span&gt;
      &lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Character count of &lt;span class="expr"&gt;#{character_count}&lt;/span&gt; is outside the range of 1-16&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

    &lt;span class="ident"&gt;input&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{secret}#{random}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;alphabet&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;abcdefghijklmnopqrstuvwxyz&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="ident"&gt;character_count&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;
      &lt;span class="ident"&gt;input&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;:&lt;span class="expr"&gt;#{alphabet}&lt;/span&gt;:&lt;span class="expr"&gt;#{character_count}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

    &lt;span class="ident"&gt;bytes&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Digest&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;MD5&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;hexdigest&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;input&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;slice&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;..(&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;character_count&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)).&lt;/span&gt;&lt;span class="ident"&gt;scan&lt;/span&gt;&lt;span class="punct"&gt;(/&lt;/span&gt;&lt;span class="regex"&gt;..&lt;/span&gt;&lt;span class="punct"&gt;/)&lt;/span&gt;
    &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

    &lt;span class="ident"&gt;bytes&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;byte&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;alphabet&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;byte&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;hex&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;alphabet&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;chr&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

    &lt;span class="ident"&gt;text&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

We can test the library using irb:

&lt;div class="console"&gt;
&lt;pre&gt;
$ irb
irb(main):001:0&gt; require 'captcha'
=&gt; true
irb(main):002:0&gt; include Captcha
=&gt; Object
irb(main):003:0&gt; get_text 'secret', 'my_random_text'
=&gt; "hnrppb"
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If we wanted to include numerical digits and require additional characters, the library enables this as well:&lt;/p&gt;

&lt;div class="console"&gt;
&lt;pre&gt;
$ irb
irb(main):001:0&gt; require 'captcha'
=&gt; true
irb(main):002:0&gt; include Captcha
=&gt; Object
irb(main):003:0&gt; get_text 'secret', 'my_random_text', 'abcdefghijklmnopqrstuvwxyz0123456789', 7
=&gt; "62m3acs"
&lt;/pre&gt;
&lt;/div&gt;

&lt;h4&gt;Conclusions&lt;/h4&gt;

&lt;p&gt;That's really all there is to the Ruby library. Once we can create a CAPTCHA image and decode its contents, we can begin to think about building an integrated Rails solution. But that's a story for another time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;image credit: &lt;a href="http://flickr.com/photos/deadhorse/"&gt;Andrew Huff&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 03 Sep 2007 09:58:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:15e30dd6-63eb-4a21-aa42-aaa9a8e7352f</guid>
      <author>Rich Apodaca</author>
      <link>http://depth-first.com/articles/2007/09/03/fighting-spam-on-the-cheap-with-captcha-a-simple-ruby-library-for-captchas-net</link>
      <category>Tools</category>
      <category>captcha</category>
      <category>captchasdotnet</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
