Ejemplo de aleatorización con BotDetect CAPTCHA ASP

Este ejemplo de aleatorización CAPTCHA muestra como puede aleatorizar fácilmente varios parámetros de control CAPTCHA, lo que puede mejorar significativamente la seguridad de protección CAPTCHA y es la mejor forma de sacarle provecho a los 50 distintos algoritmos CAPTCHA que vienen con BotDetect.

Ubicación de los archivos del proyecto de ejemplo

Por defecto, este ejemplo de proyecto es instalado en
C:\Archivos de Programa\Lanapsoft\BotDetect\ASP\v2.0\Samples\CaptchaRandomization\

También lo puede arrancar desde el Menú de Inicio:
Programas > Lanapsoft > BotDetect > ASP > v2.0 > Samples > CAPTCHA Randomization Sample

BotDetectRandomDemo.asp

Código fuente completo

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
  <head>
    <title>BotDetect CAPTCHA ASP Aleatorización Demo - Input 
      Page</title>
    <link type='text/css' rel='Stylesheet' href='FormStyle.css' />
    <script type="text/javascript" src="BotDetectScript.js">
    </script>
  </head>
  <body>
    <form name="SampleForm" id="SampleForm" method="post" 
      action="ProcessFormRandom.asp">
    <fieldset id="SampleFields">
      <legend>Sample input form</legend>
      <div class="input">
        <label for="FirstName">First Name:</label>
        <input name="FirstName" id="FirstName" type="text" 
          class="textbox" value="<%=Request("FirstName") %>" />
      </div>
      <div class="input">
        <label for="LastName">Last Name:</label>
        <input name="LastName" type="text" id="LastName" 
          class="textbox" value="<%= Request("LastName") %>" />
      </div>
    </fieldset>
    <fieldset id="CaptchaValidation">
      <legend>CAPTCHA Validation</legend>
      <div id="PromptDiv">Retype the code from the picture</div>
      <div id="CaptchaDiv">
        <div id="CaptchaImage">
          <img id="SampleForm_CaptchaImage" src="
            LanapBotDetectHandler.asp?Command=CreateImage" 
            alt='CAPTCHA Code Image' />
        </div>
        <div id="CaptchaIcons">
          <a href='LanapBotDetectHandler.asp?Command=CreateSound' 
            onclick='LBD_LoadSound("SampleForm_SoundPlaceholder", 
            "LanapBotDetectHandler.asp?Command=CreateSound");return 
            false;' title="Speak the code"><img src="speaker.gif" 
            alt="Speak the code" /></a>
          <a href='#' onclick='LBD_ReloadImage(
            "SampleForm_CaptchaImage"); return false;' title="
            Change the code"><img src="reload.gif" alt="
            Change the code" /></a>
          <div id='SampleForm_SoundPlaceholder' class="placeholder">
            &nbsp;</div>
        </div>
      </div>
      <div class="input">
        <label for="CaptchaCode">Code:</label>
        <input name="CaptchaCode" id="CaptchaCode" type="text" 
          class="textbox" onkeyup="this.value = 
            this.value.toLowerCase();" />
      </div>
      <%
      If (Request("WrongCode")<>"") Then
        Response.Write("<div><span id='CodeIncorrectLabel'>Incorrect _
          code</span></div>")
      End If
      %>
      </fieldset>
      <div id="ActionDiv">
        <input type="submit" name="ProcessForm" value="Process Form" 
          id="ProcessForm" />
      </div>
      <div id="Note">
        <span>NOTE: the Trial version will use "LANAP" instead of a 
          random code in 50% of CAPTCHA images.</span>
      </div>
    </form>
  </body>
</html>

Explicación

El formulario del ejemplo es escencialmente el mismo visto en el ejemplo sin aleatorización en el proyecto de ejemplo de un CAPTCHA, con la misma hoja de estilos, JavaScript, CAPTCHA código de generación de la imagen y sonido. La única diferencia es que la imagen no es generada con parámetros definidos en la consulta, sino aleatorizados directamente en el archivo LanapBotDetectHandler.asp.

ProcessFormRandom.asp

Código fuente completo

<%
  'Captcha validation
  Dim result, codeKey, inputCode
  result = False
  codeKey = "LanapBotDetectCode"
  inputCode = Request("CaptchaCode")

  If (Session(codeKey)<>"") Then
    code = Session(codeKey)
    result = (0 = StrComp(inputCode, code, 1))
    'each Captcha code can only be validated once
    Session(codeKey) = ""
  End If

  If result = False Then
    first_name = Request("FirstName")
    last_name = Request("LastName")
    redirect_url = "BotDetectRandomDemo.asp?FirstName=" + _
      first_name + "&LastName=" + last_name + "&WrongCode=WrongCode"
    Response.Redirect redirect_url
  End If
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>BotDetect CAPTCHA ASP Aleatorización Demo - Protected 
    Page</title>
  <link type='text/css' rel='Stylesheet' href='FormStyle.css' />
</head>
<body>
  <form name="form1" method="post" id="form1" action="ProcessForm.asp">
    <fieldset id="Properties">
      <legend>BotDetect CAPTCHA Validación passed!</legend>
      <div class="input">
        <label for="FirstName">First Name:</label>
        <input name="FirstName" id="FirstName" type="text" 
          class="textbox" readonly="readonly" 
          value="<% =Request("FirstName") %>" />
      </div>
      <div class="input">
        <label for="LastName">Last Name:</label>
        <input name="LastName" id="LastName" type="text" 
          class="textbox" readonly="readonly" 
          value="<% =Request("LastName") %>" />
      </div>
    </fieldset>
    <div id="ActionDiv">
      <a href="BotDetectRandomDemo.asp">Back to the sample form</a>
    </div>
  </form>
</body>
</html>

Explicación

La validación del código del CAPTCHA no cambia cuando aplicamos propiedades de forma aleatoria a nuestras consultas, así que las mismas explicaciones de otros ejemplos sirven para este caso, por ejemplo la del modo tradicional de validación de un CAPTCHA.

LanapBotDetectHandler.asp

Código fuente completo

<%
Dim code, codeKey, codeHash, codeHashKey, captchaId, comCaptcha

'the Captcha code is kept in Session state with this key
codeKey = "LanapBotDetectCode"
codeHashKey = "LanapBotDetectCodeHash"

'if there are multiple Captchas on tn the site, a Captcha id is 
'required to distinguish between them; otherwise, it can be ignored
captchaId = Request("CaptchaId")
If(captchaId<>"") Then
  codeKey = codeKey & "_" & captchaId
End If

If (Request("Command")="CreateImage") Then
'Captcha image generation

  'create the Captcha component instance
  Set comCaptcha = CreateObject("Lanap.BotDetect")

  'randomize the Captcha image drawing algorithm
  Dim algorithms(5)
  algorithms(0) = 28
  algorithms(1) = 36
  algorithms(2) = 44
  algorithms(3) = 25
  algorithms(4) = 39
  algorithms(5) = 48
  comCaptcha.TextStyle = RandomFromValues(algorithms)
  
  'randomize the Captcha code length
  comCaptcha.CodeLength = RandomFromRange(4, 6)
  
  'set other Captcha properties
  comCaptcha.ImageWidth = 238
  comCaptcha.ImageHeight = 50
  comCaptcha.CodeType = 0
  comCaptcha.Format = "JPEG"

  'set Captcha image Http response headers
  Response.Buffer = True
  Response.CacheControl = "no-cache, no-store, must-revalidate"
  Response.AddHeader "Pragma", "no-cache"
  Response.Expires = -1
  Response.ContentType = "image/jpeg"

  'generate the Captcha image binary data
  Dim varPicture
  varPicture = comCaptcha.CreateImage

  'save the Captcha code for sound generation and validation
  code = comCaptcha.GetValue
  Session(codeKey) = code
  'save the code hash for backward compatibility with 
	'older validation code
  codeHash = comCaptcha.GetHashValue
  Session(codeHashKey) = codeHash

  'send Captcha image binary data to the client
  Response.BinaryWrite varPicture
  Set comCaptcha = Nothing 'dispose of the Captcha component instance
  Response.End
'end Captcha image generation

ElseIf (Request("Command")="CreateSound") Then
'audio Captcha generation

  'create the Captcha component instance
  Set comCaptcha = CreateObject("Lanap.BotDetect")

  'set Http response headers
  If (Request.ServerVariables("HTTPS")="off") Then
    Response.CacheControl = "no-cache"
    Response.AddHeader "Pragma", "no-cache"
    Response.Expires = -1
  End If
  Response.Buffer = True
  Response.ContentType = "audio/x-wav"
  Response.AddHeader "content-disposition", _
    "attachment; filename=captcha.wav"
  Response.AddHeader "Content-Transfer-Encoding", "binary"
  Response.AddHeader "Connection", "Close"

  'generate the audio Captcha binary data from the saved code
  code = Session(codeKey)
  varSound = comCaptcha.CreateSoundFromCode(code)

  'send audio Captcha binary data to the client
  Response.BinaryWrite varSound
  Set comCaptcha = Nothing 'dispose of the Captcha component instance
  Response.End
'end audio Captcha generation

ElseIf (Request("Command")="Validate") Then
'Ajax Captcha validation

  Dim result
  result = False

  If (Session(codeKey)<>"") Then
    Dim inputCode
    inputCode = Request("Code")
    code = Session(codeKey)
    result = (0 = StrComp(inputCode, code, 1))
    'Ajax validation shouldn't remove the code if successful, so 
    'both client- and server-side validation can be performed and pass
    If (Not result) Then
      Session(codeKey) = ""
    End If
  End If

  'Http response headers
  Response.Buffer = True
  Response.ContentType = "text/javascript"
  Response.CacheControl = "no-cache, no-store, must-revalidate"
  Response.AddHeader "Pragma", "no-cache"
  Response.Expires = -1
  Response.AddHeader "Connection", "Close"

  'send the JSON validation result to the client
  Response.Write "{ 'result': " & LCase(CStr(result)) & " }"
  Response.End

'end Ajax Captcha validation
End If

'If neither of the above conditions was met
Response.Status = "400 Bad Request"
Response.End

'helper randomization function
Function RandomFromRange(lowerLimit, upperLimit)
  Dim num
  Randomize
  num = CInt((upperlimit - lowerlimit)*Rnd() + lowerlimit) 
  RandomFromRange = num
End Function

Function RandomFromValues(values)
  Dim num
  Randomize
  num = RandomFromRange(0, UBound(values))
  RandomFromValues = values(num)
End Function
%>

Explicación

El código de la aleatorización del CAPTCHA está ubicado en el archivo LanapBotDetectHandler.asp y no forma parte del código del formulario ASP, para que las imágenes del CAPTCHA puedan ser pedidas en múltiples ocasiones. Las imágenes son generalmente cargadas por peticiones separadas Http, la idea es lograr que cada petición de imagen al servidor sea aleatorizada y no solo algunas instancias desde la misma página.

En esta versión de LanapBotDetectHandler.asp, nosotros no leemos las propiedades de la consulta desde la cadena de petición, sino que los configuramos directamente de forma aleatoria. El largo del código es al azar y el algoritmo utilizado para desplegar la imagen del captcha es seleccionado de forma aleatoria. Para hacer estas funciones al máximo consistentes, existen límites que son definidos por dos funciones. RandomFromRange(lowerLimit, upperLimit) es una función que retorna el número dentro de los límites y RandomFromValues(values) devuelve un valor al acar dentro de una lista de valores.

Es también posible aleatorizar otras propiedades, pero la selección al azar del algoritmo es de preferencia el valor que más seguridad añade al proceso. El proceso de reconocimiento de un particular algoritmo puede llegar a ser sencillo, pero distinguir entre varios al azar es practicamente imposible. Un punto débil también es definir datos que ayuden a la compresión de la imagen por parte del robot como "escriba los cinco números de la imagen", "cuál es la letra escondida".

BotDetectScript.js

Código fuente completo

function LBD_LoadSound(soundPlaceholderId, soundLink) {
  if(document.getElementById) {
    var i = soundLink.indexOf('&d=');
    if (-1 != i) {
      soundLink = soundLink.substring(0, i);
    }
    soundLink = soundLink + '&d=' + LBD_GetTimestamp();

    var placeholder = document.getElementById(soundPlaceholderId);
    var objectSrc = "<object id='captchaSound' 
      classid='clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95' 
      height='0' width='0' style='width:0; height:0;'><param 
      name='AutoStart' value='1' /><param name='Volume' value='0' 
      /><param name='PlayCount' value='1' /><param name='FileName' 
      value='" + soundLink + "' /><embed id='captchaSoundEmbed' 
      src='"+ soundLink + "' autoplay='true' hidden='true' 
      volume='100' type='"+ LBD_GetMimeType() +"' 
      style='display:inline;' /></object>";

    placeholder.innerHTML = "";
    placeholder.innerHTML = objectSrc;
  }
}

function LBD_GetTimestamp() {
  var d = new Date();
  var t = d.getTime() + (d.getTimezoneOffset() * 60000);
  return t;
}

function LBD_GetMimeType() {
  var mimeType = "audio/x-wav";
  return mimeType;
}

var LBD_ImgId = null;
var LBD_Img = null;
var LBD_NewImg = null;
var LBD_Parent = null;
var LBD_ImagePrompt = null;

function LBD_ReloadImage(imgId) {
  if(imgId) {
    LBD_ImgId = imgId;
    LBD_Img = document.getElementById(LBD_ImgId);
    var src = LBD_Img.src;

    var i = src.indexOf('&d=');
    if (-1 != i) {
      src = src.substring(0, i);
    }
    var newSrc = src + '&d=' + LBD_GetTimestamp();

    LBD_NewImg = document.createElement('img');
    LBD_NewImg.onload = LBD_ShowImage;
    LBD_NewImg.id = LBD_Img.id;
    LBD_NewImg.alt = LBD_Img.alt;
    LBD_NewImg.src = newSrc;

    LBD_ImagePrompt = document.createElement('span');
    LBD_ImagePrompt.appendChild(document.createTextNode('loading...'));

    LBD_Parent = LBD_Img.parentNode;
    LBD_Parent.removeChild(LBD_Img);
    LBD_Parent.appendChild(LBD_ImagePrompt);
  }
}

function LBD_ShowImage() {
  if(LBD_NewImg && LBD_Parent && LBD_ImagePrompt) {
    LBD_Parent.removeChild(LBD_ImagePrompt);
    LBD_Parent.appendChild(LBD_NewImg);
  }
}

Explicación

No hay diferencias en el código de parte del cliente cuando efectuamos acciones de aleatorización, por lo tanto puede basarse en las mismas explicaciones usadas en el ejemplo de validación de CAPTCHA.

FormStyle.css

Código fuente completo

body {
  background-color: #EEEEFF;
  font-family: Verdana, Arial;
  font-size: 0.9em;
}

fieldset {
  padding: 0 10px 10px 10px;
  margin: 11px;
  width: 300px;
  display: block;
}

div.input {
  margin: 7px 0;
}

legend {
  padding: 5px;
  color: #999999;
}

label {
  display: block;
  width: 85px;
  float: left;
  text-align: right;
  padding-right: 5px;
}

input.textbox {
  width: 170px;
}

input.textboxSmall {
  width: 40px;
}

#CodeIncorrectLabel {
  color: Red;
}

#CodeCorrectLabel {
  color: Green;
}

#Note {
  padding: 0;
  margin: 11px;
  margin-bottom: -7px;
  width: 320px;
  font-size: 0.8em;
  color: Red;
}

#PromptDiv {
  padding: 0;
  margin: 0;
  margin-bottom: 8px;
}

#ActionDiv {
  padding: 0 0 10px 10px;
  margin: 11px;
  margin-right: 0;
  width: 314px;
  text-align:right;
}

fieldset #ActionDiv{
  padding: 0;
  margin: 0;
  width: auto;
  text-align:right;
}

#CaptchaDiv {
  margin: 0;
  padding: 0;
  width:265px;
  height:50px;
  padding-bottom: 5px;
}

#CaptchaImage {
  float: left;
  margin: 0;
  padding: 0;
  width:240px;
  height:50px;
}

#CaptchaIcons {
  width: 22px;
  height: 50px;
  float: right;
  text-align: left;
  margin: 0;
  padding: 0;
}

td#CaptchaIcons {
  padding-left: 3px;
}

#CaptchaIcons img {
  border: 0;
  margin: 0;
  padding: 0;
  padding-bottom: 3px;
}

*html #CaptchaIcons img {
  margin-bottom: -2px;
}

.placeholder {
  visibility: hidden;
  width:0 !important;
  height:0 !important;
}

*html .placeholder {
  display: none !important;
}

#CaptchaPreviewDiv {
  margin: 0;
  padding: 0;
  padding-bottom: 5px;
}

div.FeaturesInput {
  margin: 7px 0;
}

div.FeaturesInput label {
  width: 110px;
}

Explicación

Los estilos definidos acá son los mismos que los definidos en el ejemplo de la validación de una CAPTCHA.

Versiones Actuales de BotDetect

Advertencia

Esta página es una traducción no oficial de la página original: BotDetect CAPTCHA Randomization ASP Code Sample y puede estar incompleta, incorrecta o poco actualizada.

Última traducción del 2009-12-18. Esto se aplica para los productos BotDetect ASP.NET CAPTCHA v2.0.15 y BotDetect ASP CAPTCHA v2.0.9.

language: English Español Tiếng Việt