Skip To Main Content | Home | Sitemap | Contact
Latest Visitors: United States's flagUnited States's flagUnited States's flagUnited States's flagUnited States's flagKorea  Republic of's flagUnited States's flagRussian Federation's flagChina's flagSweden's flagNetherlands's flagUnited States's flagUnited States's flagChina's flagChina's flagPakistan's flagUnited States's flagUnited States's flagUnited States's flagSpain's flagUnited States's flagUnited States's flagUnited States's flagUnited States's flagUnited States's flag
 

How can you use images instead of characters for CAPTCHA?

My friend Oli suggests that a simpler method of preventing SPAM bots from posting to your Blog or forum is to use an image CAPTCHA test.  He has a nice write up here.  However, he incorrectly suggested classic ASP was not capable of streaming images without a third party image component. That is not true. Classic ASP can stream images and other binary data.

Streaming the images allows us to hide the true name and source of the images from any robot attempting to automatically pass our CAPTCHA test. I'm using files, you could use a database or another method.

This example simply demonstrates that classic ASP is quite capable of streaming images. I have also improved on his version by increasing the number of available image choices, making the images easier to see, and ensuring that no image is used twice on a page.

For a character based CAPTCHA example in classic ASP (not using streaming) see this example.  For an example of reading files as an include with pure JavaScript without using an <IFRAME> or a .js extension, (another thing you supposedly can not do, see this article.)

Click the three pictures of "cats" to verify.

  • verification image
  • verification image
  • verification image
  • verification image
  • verification image
  • verification image
  • verification image
  • verification image
  • verification image

NOTE: All images are freely available content available from Wikimedia Commons. [Images for Captcha]



  <%
	Option Explicit
	Session.CodePage=65001
	Response.Charset="UTF-8"
	
	' no browser caching of this page
	Response.Expires=-1
	Response.ExpiresAbsolute = Now() - 1
' do not allow proxy servers to cache this page !! to be used on all pages Response.CacheControl="private" Response.CacheControl="no-cache" Response.CacheControl="no-store"
' A temporary array used to get unique random values. ' i.e. we pick a random value, remove it from the array, and on ' subsequent random picks, we reject the value if already removed ' from the array.
Dim Unique(9) Unique(1)=1 Unique(2)=2 Unique(3)=3 Unique(4)=4 Unique(5)=5 Unique(6)=6 Unique(7)=7 Unique(8)=8 Unique(9)=9
function getRndUnique    Dim idx    idx=0    While (idx=0)       idx = Int(8 * Rnd)+1       if Unique(idx)>0 then          idx = Unique(idx)          Unique(idx)=0       else          idx=0       end if    Wend
   getRndUnique = idx end function
function getCorrect    ' choose three unique values for the image CAPTCHA     ' the values will be comma separated in ascending order.    Dim tmp, idx, out    tmp = getRndUnique & "," & getRndUnique & "," & getRndUnique    for idx=1 to 9        if Unique(idx)=0 then           out = out & idx & ","       end if    next    getCorrect = Left(out, Len(out)-1) end function
' another temporary array for getting unique images on each page
' with no repeated images
Dim UniqueImg(18)
UniqueImg(1)=1
UniqueImg(2)=2
UniqueImg(3)=3
UniqueImg(4)=4
UniqueImg(5)=5
UniqueImg(6)=6
UniqueImg(7)=7
UniqueImg(8)=8
UniqueImg(9)=9
UniqueImg(10)=10
UniqueImg(11)=11
UniqueImg(12)=12
UniqueImg(13)=13
UniqueImg(14)=14
UniqueImg(15)=15
UniqueImg(16)=16
UniqueImg(17)=17
UniqueImg(18)=18
function notUsed
   Dim idx   for idx=1 to 18        if UniqueImg(idx)>0 then           notUsed = idx          UniqueImg(idx)=0           Exit For       end if    next end function
function getRndUniqueImg    Dim idx    idx=0    While (idx=0)       idx = Int(18 * Rnd)+1       if UniqueImg(idx)>0 then          idx = UniqueImg(idx)          UniqueImg(idx)=0       else          idx=notUsed       end if    Wend    getRndUniqueImg = idx end function
Randomize
' we use session variables so the image streaming page
' will know what image to return
Session("img1") = getRndUniqueImg
Session("img2") = getRndUniqueImg
Session("img3") = getRndUniqueImg
Session("img4") = getRndUniqueImg
Session("img5") = getRndUniqueImg
Session("img6") = getRndUniqueImg
Session("img7") = getRndUniqueImg
Session("img8") = getRndUniqueImg
Session("img9") = getRndUniqueImg
' The correct image choices will be the three numbers we put in correct.
Session("correct") = getCorrect
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="author" content="Roderick Divilbiss">
<meta name="copyright" content="© 2005-2010 Roderick Divilbiss">
<meta name="MSSmartTagsPreventParsing" content="TRUE">
<title>Image Captcha :: Classic ASP Image Streaming</title>
<script type="text/javascript">
// to keep track of the image clicks
var clicked=new Array();
clicked[1]=false;
clicked[2]=false;
clicked[3]=false;
clicked[4]=false;
clicked[5]=false;
clicked[6]=false;
clicked[7]=false;
clicked[8]=false;
clicked[9]=false;
function updateClick() {
   // put the values which are clicked into our form
   var tmp='';
   for (var idx=1;idx<=9;idx++) {
     if (clicked[idx]) {
        tmp+=idx+',';
     }    }
   if (tmp.substr(tmp.length-1,1)==',') {       tmp = tmp.substr(0,tmp.length-1);    }
document.getElementById('value1').value=tmp;
}
function cMe(objI) {
var idx=parseInt(objI.id.substr(3,1));    if (objI.style.borderColor=='') {       // never clicked       objI.style.borderColor='red';       clicked[idx]=true;       updateClick();    }else if (objI.style.borderColor=='black') {        // clicked after being unclicked        objI.style.borderColor='red';        clicked[idx]=true;        updateClick();    } else {       // unclicked
objI.style.borderColor='black';
clicked[idx]=false;
updateClick();
}
   // auto submit on three clicks
   // you could remove this and add a submit button
   if (document.getElementById('value1').value.length==5) {       var myForm = document.getElementById('theForm');       myForm.submit();    } }
</script>
<style type="text/css">
#container {
   width: 350px;
   height: 300px;
}
#iarray li {
   float:left;
   margin-right:10px;
   margin-bottom: 10px;
   list-style-type:none
}
.dynamicImg {
   border:solid 2px;
   border-color:black;
   border-style:solid;
}
</style>
</head>
<body>
<!-- the container division allows us to set a width-->
<div id="container">
  <form id="theForm" name="theForm" method="post" action="Image-CAPTCHA-verify.asp">
    <ul id="iarray">
      <li><img class="dynamicImg" id="img1"
           src="streamImage.asp?c=1"
           alt="verification image"
           onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img2"
           src="streamImage.asp?c=2"
           alt="verification image"
           onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img3"
           src="streamImage.asp?c=3"
           alt="verification image"
           onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img4"
           src="streamImage.asp?c=4"
           alt="verification image"
           onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img5"
          src="streamImage.asp?c=5"
          alt="verification image"
          onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img6"
          src="streamImage.asp?c=6"
          alt="verification image"
          onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img7"
          src="streamImage.asp?c=7"
          alt="verification image"
          onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img8"
          src="streamImage.asp?c=8"
          alt="verification image"
          onclick="cMe(this);" width="75" height="75"></li>
      <li><img class="dynamicImg" id="img9"
           src="streamImage.asp?c=9"
           alt="verification image"
           onclick="cMe(this);" width="75" height="75"></li>
    </ul>
    <p><input type="hidden" id="value1" name="value1" size="20"></p>
  </form>
</div>
</body>
</html>


IMAGE STREAMER (streamImage.asp)
<%
Option Explicit
Dim img, idx, param, correct
correct = Session("correct")
param = Request.QueryString("c")
' note the image URL on the form has a parameter
' which has no association with which image is streamed
' and the parameter is only valid for a particular session.
' I am choosing three of eighteen possible cats. You could
' make this exceedingly large if you were worried about
' harvesting...which I am not. A Blog is not Fort Knox.
Dim validImage(18)
validImage(0) = "NotAvailable.jpg"
validImage(1) = "cat1.jpg"
validImage(2) = "cat2.jpg"
validImage(3) = "cat3.jpg"
validImage(4) = "cat4.jpg"
validImage(5) = "cat5.jpg"
validImage(6) = "cat6.jpg"
validImage(7) = "cat7.jpg"
validImage(8) = "cat8.jpg"
validImage(9) = "cat9.jpg"
validImage(10) = "cat10.jpg"
validImage(11) = "cat11.jpg"
validImage(12) = "cat12.jpg"
validImage(13) = "cat13.jpg"
validImage(14) = "cat14.jpg"
validImage(15) = "cat15.jpg"
validImage(16) = "cat16.jpg"
validImage(17) = "cat17.jpg"
validImage(18) = "cat18.jpg"

Dim otherImage(18)
otherImage(0) = "NotAvailable.jpg"
otherImage(1) = "not18.jpg"
otherImage(2) = "not2.jpg"
otherImage(3) = "not16.jpg"
otherImage(4) = "not4.jpg"
otherImage(5) = "not14.jpg"
otherImage(6) = "not6.jpg"
otherImage(7) = "not7.jpg"
otherImage(8) = "not8.jpg"
otherImage(9) = "not9.jpg"
otherImage(10) = "not10.jpg"
otherImage(11) = "not11.jpg"
otherImage(12) = "not12.jpg"
otherImage(13) = "not13.jpg"
otherImage(14) = "not5.jpg"
otherImage(15) = "not15.jpg"
otherImage(16) = "not3.jpg"
otherImage(17) = "not17.jpg"
otherImage(18) = "not1.jpg"
function inCorrect(num)
   Dim tmp, out
   out = false
   tmp = Split(Session("correct"),",")
   for idx = 0 to UBound(tmp)
      if CInt(tmp(idx))=CInt(num) then
         out = true
      end if
   next
   inCorrect = out
end function
' A little protection against calling the page without
' coming from the correct image CAPTCHA page.
' e.g. attempt to stop harvesting of images or
' associating any image with a URL.
if param & "x" = "x" then
   img = "NotAvailable.jpg"
else
idx = Session("img" & param)    if (idx < 1) or (idx="") or (idx & "x"="x") then       img = "NotAvailable.jpg"
   else      if InStr(correct, param)>0 then          img = validImage(idx)         validImage(idx)="NotAvailable.jpg"         Session("img" & param)=0     else        img = otherImage(idx)    end if end if end if
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
'Open a image file
objStream.Type = 1 ' adTypeBinary
objStream.Open
objStream.LoadFromFile Server.MapPath(img)

'Output the contents of the stream object
Response.ContentType = "image/jpeg"
Response.BinaryWrite objStream.Read
objStream.close
Set objStream=nothing
%>


This Weeks Most Popular Pages Newest Pages