Menubar

sábado, 30 de diciembre de 2017

Como implementar captchas en tu sitio web usando PHP

Por J. Manuel Mar H. Editar
Compartir en Facebook
Compartir en Twitter
Compartir en MeWe
Enviar a Reddit
Guardar en Internet archive
Guardar en  archive.today
Enviar por email
Captcha  Después de una larga (muuuuy larga) ausencia presento a ustedes un post más en este blog para mostrar como podemos implementar captchas en nuestra web usando PHP del lado del servidor para leer su estado. Ofrezco una disculpa por la larga ausencia y espero les sea de utilidad la información presentada.

 Como mencionaba en un artículo anterior, los captchas son mecanismos mediante los cuales es posible frenar (hasta cierto punto) la invasión de spambots en nuestro blog, consisten básicamente en un sistema en el cual tenemos que realizar una acción al azar y que solo es legible para un ser humano, cosa que un programa no podría hacer, si la verificación es exitosa entonces podremos acceder al recurso que estamos solicitando, de lo contrario obtendremos un mensaje de error.

Publicidad


  Existen diversos sistemas de captchas en la red, desde muy simples hasta muy completos. Si bien es cierto que los captchas muy complejos pueden garantizar que spambots no nos invadan, también es verdad que pueden hacer que el usuario se desespere y simplemente se vaya de nuestra web, como se explica en el artículo "Los Captchas, una medida de protección (y de molestia... a veces)" perteneciente a este mismo blog.

  Entonces, si queremos implementar un captcha en nuestra web, pero no queremos frustrar al visitante, lo mejor sería montar un captcha simple. Es por eso que este artículo va a mostrar como montar cuatro diferentes captchas en nuestra web.

Securimage


  Securimage es un sistema de captchas muy simple, genera un texto en formato imagen (que no puede ser leído por un spambot, pero si por un ojo humano), ingresamos ese texto en la caja de texto para efectuar la validación, si hubo éxito el sistema que implementemos nos debe permitir el paso, de lo contrario mostraremos un mensaje de error.

En este primer ejemplo veremos como implementar el captcha mediante el archivo test.html

<html>
<head>
<title>Captcha Securimage</title>
</head>
<body>

<form method="post" action="verify.php" style="display: inline;">

<table border="0">
<tr>
<td valign="top">Su nombre completo:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="fullname"></td>
</tr>
<tr>
<td valign="top">Su Email:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="email"></td>
</tr>
<tr>
<td valign="top">Comentarios:</td>
</tr>
<tr>
<td valign="top"><textarea maxlength="255" name="comments" style="width: 100%;" rows="7"></textarea></td>
</tr>
<tr>
<td valign="top">

<!-- CAPTCHA SECTION -->

<table border="0">
<tr>
<td valign="top"><img src="../securimage/securimage_show.php" border="0" width="166" height="88" alt="Codigo de seguridad" name="captcha" id="captcha"><audio autoplay name="audio" id="audio"><source src="" type="audio/mpeg"></audio></td>
</tr>
<tr>
<td valign="top" nowrap="true"><font class="bold_text">Ingrese c&oacute;digo de seguridad:</font></td>
</tr>
<tr>
<td valign="bottom" nowrap="true"><input type="text" name="captcha_code" style="width: 101px" maxlength="255">&nbsp;<a href="#" onclick="document.getElementById('audio').src = '../securimage/securimage_play.php?' + Math.random(); return false"><img src="../securimage/images/audio_icon.gif" width="22" height="20" border="0" alt="Audio del captcha" align="absmiddle"></a>&nbsp;<a href="#" onclick="document.getElementById('captcha').src = '../securimage/securimage_show.php?' + Math.random(); return false"><img src="../securimage/images/refresh.gif" width="22" height="20" border="0" alt="Nuevo código de seguridad" align="absmiddle"></a>&nbsp;<font size="2" class="normal_text"><- Recargar im&aacute;gen</font></td>
</tr>
</table>

<!-- CAPTCHA SECTION -->

</td>
</tr>
<tr>
<td valign="top">

<table border="0">
<tr>
<td valign="middle"><input type="submit" value="Acceso" style="height: 30px;"></td>
<td valign="middle"><input type="reset" value="Borrar" style="height: 30px;"></td>
</tr>
</table>

</td>
</tr>
</table>

</form>

</body>
</html>

Esta sería la salida en pantalla de nuestro sistema de captcha:
Securimage























 Como podemos ver en el código, tenemos que tener instalado nuestro sistema de captcha en el servidor PHP donde vayamos a ejecutar nuestra prueba, (../securimage/securimage_show.php) el cual generará la imagen con el texto a verificar. Securimage puede ser descargado desde su web oficial https://www.phpcaptcha.org/ y se distribuye bajo licencia BSD.

  Ingresado el texto a verificar presionamos el botón "Acceso" para intentar verificar si el texto ingresado es correcto o no, lo cual nos lleva al documento verify.php

<?

  if(isset($_POST["fullname"]))
    $fullname = trim($_POST["fullname"]);
  else
    $fullname = "";
    
  if(isset($_POST["email"]))
    $email = trim($_POST["email"]);
  else
    $email = "";
    
  if(isset($_POST["comments"]))
    $comments = trim($_POST["comments"]);
  else
    $comments = "";

  if(isset($_POST["captcha_code"]))
    $captcha = trim($_POST["captcha_code"]);
  else
    $captcha = "";
    
  include("../securimage/securimage.php");
  $securimage = new Securimage(); 

  if($securimage->check(trim($captcha)) == true)
    $captcha_status = true;
else
  $captcha_status = false;

?>
<html>
<head>
<title>Verificar captcha Securimage</title>
</head>
<body>

<?

  global $fullname, $email, $comments, $captcha_status;

  if($captcha_status == true)
  {

  echo "<font style='font-weight: bold;'>OK</font>, redireccionando, espere un momento por favor..."."\n";
  echo "<br>"."\n";
  echo "<form name='frm' action='target.php' method='post' style='display: inline;'>"."\n";   
  echo "<input type='hidden' name='fullname' value='".trim($fullname)."'>"."\n";
  echo "<input type='hidden' name='email' value='".trim($email)."'>"."\n";
  echo "<input type='hidden' name='comments' value='".trim($comments)."'>"."\n";
  echo "</form>"."\n";
  echo "<br>"."\n";
  echo "<script language='JavaScript'>"."\n";
  echo "setTimeout('document.frm.submit();', 3000);"."\n";
  echo "</script>"."\n";
  
}
else
  echo "<font style='font-weight: bold; color: red;'>ERROR</font>, el c&oacute;digo ingresado es incorrecto. Haga clic <a href='test.html'>aqu&iacute;</a> para intentarlo de nuevo.";

?>

</body>
</html>

 Aquí requerimos hacer uso nuevamente del script de securimage, por lo que lo incluimos en el archivo, y luego solicitamos la verificación del texto ingresado. Si es correcto redireccionaremos al usuario a una web (pasamos todos los parámetros de la web inicial), pero si no es correcto el texto, entonces mostraremos un mensaje de error con la opción de regresar a la pantalla inicial.

 Muy simple, ¿no?, bien, solo hay un detalle a mencionar. Securimage no diferencia entre mayúsculas y minúsculas ingresadas, tal vez sea un bug (tengo una versión antigua, la número 2, mientras que en la web van en la 3.6.6) que espero ya halla sido reparado en las versiones posteriores.

  Dentro de la carpeta del script securimage podemos editar el archivo secureimage_show.php y con ello editar las configuraciones de la imagen a mostrar en pantalla.

En mi caso estoy usando la siguiente configuración:

$img->perturbation = 0.65; // 1.0 = high distortion, higher numbers = more distortion
$img->text_color = new Securimage_Color("#EAEAEA");
$img->text_transparency_percentage = 65; // 100 = completely transparent
$img->num_lines = 2;
$img->line_color = new Securimage_Color("#555555");
$img->show('backgrounds/bg6.png');

  Como pueden ver, se trata de un script muy simple, la configuración que elegí hace que no sea muy difícil de leer por un usuario y hasta el momento me ha dado buenos resultados, ahora veamos como podemos implementarlo igualmente por PHP, pero usando AJAX.

  AJAX es una tecnología que permite a un sitio web mediante JavaScript recuperar el contenido de un archivo y mostrarlo en el navegador web  del usuario, de esta manera no hay necesidad de direccionar al visitante a un sitio web para ver los resultados de la ejecución de un script (aunque si hay que esperar unos segundos, sería bueno poner un aviso para que el visitante no piense que no está pasando nada mientras espera).

Veamos ahora el mismo script captcha pero usando AJAX.

<html>
<head>
<title>Captcha Securimage</title>
<script language="JavaScript" src="../../jquery/jquery.js">
</script>
<script language="JavaScript">
<!--

//thanks to http://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric
function isNumeric(str)
{

  var RE = /^-{0,1}\d*\.{0,1}\d+$/;
  return (RE.test(str));
  
}

//thanks to http://hayageek.com/jquery-ajax-post/
function getFileFromAJAXPOSTMethod(url, valuepairstr, timeout)
{

  var html = "";
  
  jQuery.ajax({
  
    url: url,
    type: "post",
    data: valuepairstr,
      success: function(data, textStatus, jqXHR) {
        html = data;
      },
      async: false,
      timeout: timeout
  
});

  return html;

}

function verify()
{

  var status = "";

  if(document.frm.captcha_code.value == "" || document.frm.captcha_code.value == null || document.frm.captcha_code.value == "undefined")
    alert("Debe de ingresar el código de seguridad para poder continuar...");
  else
  {
  
    status = getFileFromAJAXPOSTMethod("verify.php?id=" + Math.random(), "captcha_code=" + document.frm.captcha_code.value, 10000);
    
    if(status == "")
    alert("Sin respuesta o no se encuentra el archivo en el servidor.");
  else
  {

   try
     {
      
       if(isNumeric(String(status)) == false)
         alert("Respuesta invalida del servidor.\n------------------------------------------\n" + status);
else
{
 
   switch(parseInt(status))
{

   case 0:
 
alert("Sin respuesta o no se encuentra el archivo en el servidor.");
break;
 
case 200: //OK
 
   document.getElementById("cmdAccess").disabled = false;
   alert("Captcha resuelto correctamente, presione el botón 'Acceso' para continuar.");
   
break;
 
case 400: //Incomplete message to send

alert("Datos incompletos enviados al servidor.");
break;
 
case 403: //Denied access

alert("Código de seguridad incorrecto, intente de nuevo por favor.");
break;
 
default:
 
alert("Error desconocido desde el servidor: " + status);
break;
   
   }    
 
   } 
       
     }
     catch(e)
     {
        alert("Error critico: " + e.toString());
}
    

    
  }

}

-->
</script>
</head>
<body>

<form method="post" name="frm" action="target.php" style="display: inline;">

<table border="0">
<tr>
<td valign="top">Su nombre completo:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="fullname"></td>
</tr>
<tr>
<td valign="top">Su Email:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="email"></td>
</tr>
<tr>
<td valign="top">Comentarios:</td>
</tr>
<tr>
<td valign="top"><textarea maxlength="255" name="comments" style="width: 100%;" rows="7"></textarea></td>
</tr>
<tr>
<td valign="top">

<!-- CAPTCHA SECTION -->

<table border="0">
<tr>
<td valign="top"><img src="../securimage/securimage_show.php" border="0" width="166" height="88" alt="Codigo de seguridad" name="captcha" id="captcha"><audio autoplay name="audio" id="audio"><source src="" type="audio/mpeg"></audio></td>
</tr>
<tr>
<td valign="top" nowrap="true"><font class="bold_text">Ingrese c&oacute;digo de seguridad:</font></td>
</tr>
<tr>
<td valign="bottom" nowrap="true"><input type="text" name="captcha_code" style="width: 101px" maxlength="255">&nbsp;<a href="#" onclick="document.getElementById('audio').src = '../securimage/securimage_play.php?' + Math.random(); return false"><img src="../securimage/images/audio_icon.gif" width="22" height="20" border="0" alt="Audio del captcha" align="absmiddle"></a>&nbsp;<a href="#" onclick="document.getElementById('captcha').src = '../securimage/securimage_show.php?' + Math.random(); return false"><img src="../securimage/images/refresh.gif" width="22" height="20" border="0" alt="Nuevo código de seguridad" align="absmiddle"></a>&nbsp;<font size="2" class="normal_text"><- Recargar im&aacute;gen</font></td>
</tr>
</table>

<!-- CAPTCHA SECTION -->

</td>
</tr>
<tr>
<td valign="top">

<table border="0">
<tr>
<td valign="middle"><input type="button" value="Verificar" style="height: 30px;" onclick="javascript:verify();"></td>
<td valign="middle"><input type="submit" value="Acceso" style="height: 30px;" id="cmdAccess" disabled></td>
<td valign="middle"><input type="reset" value="Borrar" style="height: 30px;"></td>
</tr>
</table>

</td>
</tr>
</table>

</form>

</body>
</html>

Esta sería la salida en pantalla de nuestro sistema de captcha:
Securimage























 Como podemos ver, ahora tenemos un par de botones rotulados como "Verificar" y "Acceso". El botón "Acceso" ahora está desactivado, hay que presionar el botón "Verificar" para que vía AJAX se verifique si el código ingresado pasa la prueba captcha o no.

 Cuando se presiona el botón, este llama a una función javascript llamada "verify", esta a su vez llama al archivo "verify.php", pero, a diferencia del ejemplo anterior aquí solo se devuelven estados para indicar si la verificación fue exitosa o no, ¿porqué hacemos esto?, porque ese archivo se devuelve al cliente sin que este esté consciente de que algo está pasando. No tiene sentido dar una salida HTML del proceso de verificación puesto que lo nos interesa únicamente es saber si paso la inspección o no, el cliente no ve nada en pantalla en ningún momento. Si hubo éxito habilitaremos el botón "Acceso", de lo contrario mostraremos un mensaje de error.

Este es el contenido del archivo verify.php

<?

  if(isset($_POST["captcha_code"]))
    $captcha = trim($_POST["captcha_code"]);
  else
    $captcha = "";
    
  include("../securimage/securimage.php");
  $securimage = new Securimage(); 
  
  if(trim($captcha) == "")
    echo "400";
  else
  {

  if($securimage->check(trim($captcha)) == true)
      $captcha_status = true;
  else
    $captcha_status = false;
  
  if($captcha_status == true)
      echo "200";
    else
      echo "403";
      
  }

?>

  Ahora al presionar dicho botón ya nos dirigimos a la web aprobada, mientras no resolvamos el captcha no podremos pasar. La diferencia entre los dos scripts es:

  •   Del modo tradicional tenemos que dirigir nuestro sistema a un documento en PHP, el cual recolecta los datos ingresados en el captcha, verifica si corresponden con la imagen y si es correcto redirecciona al sitio web deseado, de lo contrario muestra un mensaje de error. En resumen se requiere pasar por tres archivos para tener éxito.
  •   Mediante AJAX, se valida el captcha desde la misma web, si hay éxito hay un acceso al archivo deseado, de lo contrario un mensaje de error, es todo.

  Como pueden ver, mediante AJAX es más rápido todo, incluso se podría suprimir tener que habilitar el botón una vez verificado, esto es solo para mostrar que la verificación tuvo éxito, pero es posible suprimir este paso y dar un acceso más veloz.

  En resumen securimage es un script muy simple de usar, que nos permite montar un captcha en nuestra web y verificar su estado usando PHP, todo ello sin mayores complicaciones.

Quick captcha


 Quick captcha (http://www.web1marketing.com/resources/tools/quickcaptcha/) es un script muy similar a securimage. Prácticamente el funcionamiento es el mismo, con la única ventaja de que este script si valida correctamente el texto introducido y hace distinción entre mayúsculas y minúsculas ingresadas.

  Se distribuye bajo licencia GPL. Puesto que es muy similar a securimage no voy a entrar en detalles excesivos entonces, la explicación del funcionamiento de securimage aplica para quick captcha.

Veamos en primer lugar como podemos usar quick captcha en un portal web (archivo test.html):

<html>
<head>
<title>Quick captcha</title>
</head>
<body>

<form method="post" action="verify.php" style="display: inline;">

<table border="0">
<tr>
<td valign="top">Su nombre completo:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="fullname"></td>
</tr>
<tr>
<td valign="top">Su Email:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="email"></td>
</tr>
<tr>
<td valign="top">Comentarios:</td>
</tr>
<tr>
<td valign="top"><textarea maxlength="255" name="comments" style="width: 100%;" rows="7"></textarea></td>
</tr>
<tr>
<td valign="top">

<!-- CAPTCHA SECTION -->

<table border="0">
<tr>
<td valign="top"><img src="../quickcaptcha/imagebuilder.php" border="0" alt="Codigo de seguridad" name="captcha" id="captcha"></td>
</tr>
<tr>
<td valign="top" nowrap="true"><font class="bold_text">Ingrese c&oacute;digo de seguridad:</font></td>
</tr>
<tr>
<td valign="bottom" nowrap="true"><input type="text" name="captcha_code" style="width: 101px" maxlength="255">&nbsp;<a href="#" onclick="document.getElementById('captcha').src = '../quickcaptcha/imagebuilder.php?' + Math.random(); return false"><img src="../../securimage/securimage/images/refresh.gif" width="22" height="20" border="0" alt="Nuevo código de seguridad" align="absmiddle"></a>&nbsp;<font size="2" class="normal_text"><- Recargar im&aacute;gen</font></td>
</tr>
</table>

<!-- CAPTCHA SECTION -->

</td>
</tr>
<tr>
<td valign="top">

<table border="0">
<tr>
<td valign="middle"><input type="submit" value="Acceso" style="height: 30px;"></td>
<td valign="middle"><input type="reset" value="Borrar" style="height: 30px;"></td>
</tr>
</table>

</td>
</tr>
</table>

</form>

</body>
</html>

  El código fuente es prácticamente el mismo que en el caso de securimage, la unica diferencia es el script para generar el captcha, en lugar de usar la línea ../securimage/securimage_show.php se usa ../quickcaptcha/imagebuilder.php que corresponde al generador de imágenes de quick captcha, respectivamente. Sin embargo, quick captcha no tiene soporte para reproducir en audio las letras generadas en pantalla, cosa que si es posible con securimage.

Salida en pantalla usando quick captcha:
Quick captcha




















 El resto del código fuente funciona igual: El usuario presiona el botón "Acceso", si la validación es exitosa se direcciona entonces al usuario hacia una web permitida, de lo contrario se muestra un mensaje de error. Veamos entonces el archivo de validación del captcha.

verify.php
<?

  session_start();
  
  if(isset($_POST["fullname"]))
    $fullname = trim($_POST["fullname"]);
  else
    $fullname = "";
    
  if(isset($_POST["email"]))
    $email = trim($_POST["email"]);
  else
    $email = "";
    
  if(isset($_POST["comments"]))
    $comments = trim($_POST["comments"]);
  else
    $comments = "";

  if(isset($_POST["captcha_code"]))
    $captcha = trim($_POST["captcha_code"]);
  else
    $captcha = "";
    
  $string = trim($_SESSION['string']); 

  if(trim($string) == trim($captcha))
    $captcha_status = true;
else
  $captcha_status = false;
  
session_destroy(); 

?>
<html>
<head>
<title>Verificar quick captcha</title>
</head>
<body>

<?

  global $fullname, $email, $comments, $captcha_status;

  if($captcha_status == true)
  {

  echo "<font style='font-weight: bold;'>OK</font>, redireccionando, espere un momento por favor..."."\n";
  echo "<br>"."\n";
  echo "<form name='frm' action='target.php' method='post' style='display: inline;'>"."\n";   
  echo "<input type='hidden' name='fullname' value='".trim($fullname)."'>"."\n";
  echo "<input type='hidden' name='email' value='".trim($email)."'>"."\n";
  echo "<input type='hidden' name='comments' value='".trim($comments)."'>"."\n";
  echo "</form>"."\n";
  echo "<br>"."\n";
  echo "<script language='JavaScript'>"."\n";
  echo "setTimeout('document.frm.submit();', 3000);"."\n";
  echo "</script>"."\n";
  
}
else
  echo "<font style='font-weight: bold; color: red;'>ERROR</font>, el c&oacute;digo ingresado es incorrecto. Haga clic <a href='test.html'>aqu&iacute;</a> para intentarlo de nuevo.";

?>

</body>
</html>

 Del mismo modo, podemos configurar la apariencia del captcha a través del archivo settings.php presente en la carpeta del script que hemos instalado en nuestro servidor.

// A value between 0 and 100 describing how much color overlap
// there is between text and other objects.  Lower is more
// secure against bots, but also harder to read.
$contrast = 100;

// Various obfuscation techniques.
$num_polygons = 0; // Number of triangles to draw.  0 = none
$num_ellipses = 4;  // Number of ellipses to draw.  0 = none
$num_lines = 0;  // Number of lines to draw.  0 = none
$num_dots = 0;  // Number of dots to draw.  0 = none

$min_thickness = 2;  // Minimum thickness in pixels of lines
$max_thickness = 8;  // Maximum thickness in pixles of lines
$min_radius = 5;  // Minimum radius in pixels of ellipses
$max_radius = 15;  // Maximum radius in pixels of ellipses

// How opaque should the obscuring objects be. 0 is opaque, 127
// is transparent.
$object_alpha = 75;

Veamos ahora el ejemplo usando AJAX:
<html>
<head>
<title>Quick Captcha</title>
<script language="JavaScript" src="../../jquery/jquery.js">
</script>
<script language="JavaScript">
<!--

//thanks to http://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric
function isNumeric(str)
{

  var RE = /^-{0,1}\d*\.{0,1}\d+$/;
  return (RE.test(str));
  
}

//thanks to http://hayageek.com/jquery-ajax-post/
function getFileFromAJAXPOSTMethod(url, valuepairstr, timeout)
{

  var html = "";
  
  jQuery.ajax({
  
    url: url,
    type: "post",
    data: valuepairstr,
      success: function(data, textStatus, jqXHR) {
        html = data;
      },
      async: false,
      timeout: timeout
  
});

  return html;

}

function verify()
{

  var status = "";

  if(document.frm.captcha_code.value == "" || document.frm.captcha_code.value == null || document.frm.captcha_code.value == "undefined")
    alert("Debe de ingresar el código de seguridad para poder continuar...");
  else
  {
  
    status = getFileFromAJAXPOSTMethod("verify.php?id=" + Math.random(), "captcha_code=" + document.frm.captcha_code.value, 10000);
    
    if(status == "")
    alert("Sin respuesta o no se encuentra el archivo en el servidor.");
  else
  {

   try
     {
      
       if(isNumeric(String(status)) == false)
         alert("Respuesta invalida del servidor.\n------------------------------------------\n" + status);
else
{
 
   switch(parseInt(status))
{

   case 0:
 
alert("Sin respuesta o no se encuentra el archivo en el servidor.");
break;
 
case 200: //OK
 
   document.getElementById("cmdAccess").disabled = false;
   alert("Captcha resuelto correctamente, presione el botón 'Acceso' para continuar.");
   
break;
 
case 400: //Incomplete message to send

alert("Datos incompletos enviados al servidor.");
break;
 
case 403: //Denied access

alert("Código de seguridad incorrecto, intente de nuevo por favor.");
break;
 
default:
 
alert("Error desconocido desde el servidor: " + status);
break;
   
   }    
 
   } 
       
     }
     catch(e)
     {
        alert("Error critico: " + e.toString());
}
    

    
  }

}

-->
</script>
</head>
<body>

<form method="post" name="frm" action="target.php" style="display: inline;">

<table border="0">
<tr>
<td valign="top">Su nombre completo:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="fullname"></td>
</tr>
<tr>
<td valign="top">Su Email:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="email"></td>
</tr>
<tr>
<td valign="top">Comentarios:</td>
</tr>
<tr>
<td valign="top"><textarea maxlength="255" name="comments" style="width: 100%;" rows="7"></textarea></td>
</tr>
<tr>
<td valign="top">

<!-- CAPTCHA SECTION -->

<table border="0">
<tr>
<td valign="top"><img src="../quickcaptcha/imagebuilder.php" border="0" alt="Codigo de seguridad" name="captcha" id="captcha"></td>
</tr>
<tr>
<td valign="top" nowrap="true"><font class="bold_text">Ingrese c&oacute;digo de seguridad:</font></td>
</tr>
<tr>
<td valign="bottom" nowrap="true"><input type="text" name="captcha_code" style="width: 101px" maxlength="255">&nbsp;<a href="#" onclick="document.getElementById('captcha').src = '../quickcaptcha/imagebuilder.php?' + Math.random(); return false"><img src="../../securimage/securimage/images/refresh.gif" width="22" height="20" border="0" alt="Nuevo código de seguridad" align="absmiddle"></a>&nbsp;<font size="2" class="normal_text"><- Recargar im&aacute;gen</font></td>
</tr>
</table>

<!-- CAPTCHA SECTION -->

</td>
</tr>
<tr>
<td valign="top">

<table border="0">
<tr>
<td valign="middle"><input type="button" value="Verificar" style="height: 30px;" onclick="javascript:verify();"></td>
<td valign="middle"><input type="submit" value="Acceso" style="height: 30px;" id="cmdAccess" disabled></td>
<td valign="middle"><input type="reset" value="Borrar" style="height: 30px;"></td>
</tr>
</table>

</td>
</tr>
</table>

</form>

</body>
</html>

Se muestra la salida en pantalla:
Quick captcha




















Ahora veamos la validación del captcha usando AJAX:
<?

  session_start();
  
  if(isset($_POST["fullname"]))
    $fullname = trim($_POST["fullname"]);
  else
    $fullname = "";
    
  if(isset($_POST["email"]))
    $email = trim($_POST["email"]);
  else
    $email = "";
    
  if(isset($_POST["comments"]))
    $comments = trim($_POST["comments"]);
  else
    $comments = "";

  if(isset($_POST["captcha_code"]))
    $captcha = trim($_POST["captcha_code"]);
  else
    $captcha = "";
    
  $string = trim($_SESSION['string']); 
  
session_destroy(); 
  
  if(trim($captcha) == "")
    echo "400";
  else
  {

  if(trim($string) == trim($captcha))
      $captcha_status = true;
  else
    $captcha_status = false;
  
  if($captcha_status == true)
      echo "200";
    else
      echo "403";
      
  }

?>

 Si hubo éxito se devuelve el estado 200, 403 en caso de error, y ese código se intercepta en la función verify del archivo test.html, así sabremos si la verificación fue exitosa o no, y darle el acceso al usuario o no.

Qaptcha


 Qaptcha (https://www.jqueryscript.net/form/Draggable-jQuery-Captcha-Plugin-QapTcha.html) es un script de captchas, que a diferencia de los dos anteriores no genera números y letras al azar en pantalla, sino un control deslizante. Cuando el usuario desliza el control (se supone que un spambot no puede hacerlo) entonces el captcha queda validado, se habilitará el botón "Acceso" y se dará acceso al usuario al archivo solicitado.

Qaptcha




















La licencia de qaptcha es MIT y veamos como podemos implementarlo en nuestra web:

Archivo test.html
<html>
<head>
<title>Qaptcha</title>
<link rel="stylesheet" href="QapTcha.jquery.css" type="text/css" />
<script type="text/javascript" src="../jquery/jquery.js"></script>
<script type="text/javascript" src="../jquery/jquery-ui.js"></script>
<script type="text/javascript" src="../jquery/jquery.ui.touch.js"></script>
<script type="text/javascript" src="QapTcha.jquery.js"></script>
<script type="text/javascript">
$(document).ready(function()
{

  $('.QapTcha').QapTcha({
      autoSubmit : true,
      autoRevert : true,
  txtLock : 'Bloqueado: Desbloquear para enviar!',
  txtUnlock : 'Desbloqueado: Ya se puede enviar!'
    });
    
});  
</script>
</head>
<body>

<form method="post" action="target.php" style="display: inline;">

<table border="0">
<tr>
<td valign="top">Su nombre completo:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="fullname"></td>
</tr>
<tr>
<td valign="top">Su Email:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="email"></td>
</tr>
<tr>
<td valign="top">Comentarios:</td>
</tr>
<tr>
<td valign="top"><textarea maxlength="255" name="comments" style="width: 100%;" rows="7"></textarea></td>
</tr>
<tr>
<td valign="top">

<!-- CAPTCHA SECTION -->
<div class="QapTcha"></div>
<!-- CAPTCHA SECTION -->

</td>
</tr>
<tr>
<td valign="top">

<table border="0">
<tr>
<td valign="middle"><input type="submit" value="Acceso" style="height: 30px;"></td>
<td valign="middle"><input type="reset" value="Borrar" style="height: 30px;"></td>
</tr>
</table>

</td>
</tr>
</table>

</form>

</body>
</html>

  Como podemos ver, se requiere de JQuery instalado para que qaptcha pueda funcionar, igualmente desde su web de descarga hay que instalar todos los archivos restantes (el archivo a descargar contiene JQuery). Una vez tengamos eso nuestra web ya mostrará un control deslizante (tal como se muestra la imagen al inicio de esta sección).

  Aquí no hay necesidad de un archivo para verificar el captcha, pues el mismo control es la verificación, un spambot en teoría no puede deslizar el control. Si el desplazamiento ha tenido éxito se habilita el botón y se le da paso al usuario.

Nota: el control viene con una imagen para generar el área deslizable, la cual a mi gusto es poco bonita. Me tomé la labor de editar otra imagen, la cual pueden descargar haciendo clic en este enlace, está basada en el ejemplo de esta web: https://www.script-tutorials.com/top10-really-user-friendly-captchas/.

Solvemedia


  Hasta aquí, los tres ejemplos anteriores requieren descargar un archivo zip por lo general, descomprimirlo en el servidor (o donde estemos haciendo pruebas), ligar esos archivos con nuestro proyecto y ya tenemos el captcha listo. Esto tiene la ventaja de que a menos que nuestro servidor deje de funcionar el captcha será operativo, pero la desventaja de tener que actualizar esos archivos cada vez que halla mejoras o correcciones de errores.

  Solvemedia por su parte pone a disposición de los usuarios un sistema de captcha que funciona en su servidor. La ventaja es que no necesitamos estarlo actualizando para tenerlo al día, solvemedia se encarga de ello, pero si solvemedia deja de funcionar nuestro captcha simplemente no funcionará.

  Si te interesa probarlo de todas maneras, lo primero es registrarnos en solvemedia para que nos den acceso a su API, para ello visitaremos la web http://portal.solvemedia.com/portal/public/signup, registraremos nuestro sitio web y obtendremos las claves de acceso para conectar nuestro sitio web con el script de solvemedia.

  Luego, siguiendo las instrucciones del portal http://wsnippets.com/integrate-solve-media-captcha-php/ vemos que hay que bajar la librería de solvemedia, este archivo hay que colocarlo en nuestra web y va a ser el puente entre nuestro proyecto y solvemedia, sin el, no funciona el captcha.

Una vez ya todo listo, este es el archivo test.php
<html>
<head>
<title>Solvemedia captcha</title>
</head>
<body>

<form method="post" action="verify.php" style="display: inline;">

<table border="0">
<tr>
<td valign="top">Su nombre completo:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="fullname"></td>
</tr>
<tr>
<td valign="top">Su Email:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="email"></td>
</tr>
<tr>
<td valign="top">Comentarios:</td>
</tr>
<tr>
<td valign="top"><textarea maxlength="255" name="comments" style="width: 100%;" rows="7"></textarea></td>
</tr>
<tr>
<td valign="top">

<!-- CAPTCHA SECTION -->

<?

 require_once("../solvemedialib.php");
 echo solvemedia_get_html("your_challenge_key");

?>

<!-- CAPTCHA SECTION -->

</td>
</tr>
<tr>
<td valign="top">

<table border="0">
<tr>
<td valign="middle"><input type="submit" value="Acceso" style="height: 30px;"></td>
<td valign="middle"><input type="reset" value="Borrar" style="height: 30px;"></td>
</tr>
</table>

</td>
</tr>
</table>

</form>

</body>
</html>

Vemos que solvemedia está creando el captcha directamente mediante las líneas:

<?

 require_once("../solvemedialib.php");
 echo solvemedia_get_html("your_challenge_key");

?>

  El resto del procedimiento es igual: enviamos el resultado de la captura del captcha por parte del usuario al archivo verify.php, si hubo éxito lo direccionará a una web permitida, de lo contrario mostrará un mensaje de error.

Solvemedia

























 Este es el resultado del archivo test.php, solvemedia muestra su script. Ahora veamos el archivo de la verificación del captcha.

verify.php
<?  

  if(isset($_POST["fullname"]))
    $fullname = trim($_POST["fullname"]);
  else
    $fullname = "";
    
  if(isset($_POST["email"]))
    $email = trim($_POST["email"]);
  else
    $email = "";
    
  if(isset($_POST["comments"]))
    $comments = trim($_POST["comments"]);
  else
    $comments = "";

  if(isset($_POST["captcha_code"]))
    $captcha = trim($_POST["captcha_code"]);
  else
    $captcha = "";
    
  require_once("../solvemedialib.php"); 

  $privkey="your_verify_key";
$hashkey="your_hash_key";
$solvemedia_response = solvemedia_check_answer($privkey,
$_SERVER["REMOTE_ADDR"],
$_POST["adcopy_challenge"],
$_POST["adcopy_response"],
$hashkey);

if($solvemedia_response->is_valid)
    $captcha_status = true;
else
  $captcha_status = false;

?>
<html>
<head>
<title>Verificar captcha Solvemedia</title>
</head>
<body>

<?

  global $fullname, $email, $comments, $captcha_status;

  if($captcha_status == true)
  {

  echo "<font style='font-weight: bold;'>OK</font>, redireccionando, espere un momento por favor..."."\n";
  echo "<br>"."\n";
  echo "<form name='frm' action='target.php' method='post' style='display: inline;'>"."\n";   
  echo "<input type='hidden' name='fullname' value='".trim($fullname)."'>"."\n";
  echo "<input type='hidden' name='email' value='".trim($email)."'>"."\n";
  echo "<input type='hidden' name='comments' value='".trim($comments)."'>"."\n";
  echo "</form>"."\n";
  echo "<br>"."\n";
  echo "<script language='JavaScript'>"."\n";
  echo "setTimeout('document.frm.submit();', 3000);"."\n";
  echo "</script>"."\n";
  
}
else
  echo "<font style='font-weight: bold; color: red;'>ERROR</font>, el c&oacute;digo ingresado es incorrecto. Haga clic <a href='test.php'>aqu&iacute;</a> para intentarlo de nuevo.";

?>

</body>
</html>

 Las claves para las variables $privkey y $hashkey las obtenemos al registrar nuestro sitio en el sistema de apis de solvemedia. Ahora haremos lo mismo pero usando AJAX.

test.php
<html>
<head>
<title>Captcha Solvemedia</title>
<script language="JavaScript" src="../../jquery/jquery.js">
</script>
<script language="JavaScript">
<!--

/********************************* FUNCION TRIM EN JAVASCRIPT, TOMADA DE http://www.lawebdelprogramador.com/codigo/codigo.php?idp=178&id=45&texto=JavaScript *********************************/

function trim(str)
{

  var i;
  
  if(str != null)
  {
  
     for(i=0; i<str.length; i++)
     {

       if(str.charAt(i)== " ")
     str = str.substring(i+1, str.length);
   else
     break;

     }
  
     for(i=str.length-1; i>=0; i=str.length-1)
     {
  
       if(str.charAt(i)== " ")
     str = str.substring(0,i);
   else
     break;

     }

  }
  else
    str = "";
  
  return str;
  
}

/********************************* FUNCION TRIM EN JAVASCRIPT, TOMADA DE http://www.lawebdelprogramador.com/codigo/codigo.php?idp=178&id=45&texto=JavaScript *********************************/

//thanks to http://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric
function isNumeric(str)
{

  var RE = /^-{0,1}\d*\.{0,1}\d+$/;
  return (RE.test(str));
  
}

//thanks to http://hayageek.com/jquery-ajax-post/
function getFileFromAJAXPOSTMethod(url, valuepairstr, timeout)
{

  var html = "";
  
  jQuery.ajax({
  
    url: url,
    type: "post",
    data: valuepairstr,
      success: function(data, textStatus, jqXHR) {
        html = data;
      },
      async: false,
      timeout: timeout
  
});

  return html;

}

function verify()
{

  var status = "";

  if(trim(document.frm.adcopy_response.value) == "" || document.frm.adcopy_response.value == null || trim(document.frm.adcopy_response.value).toLowerCase() == "undefined")
    alert("Debe de ingresar el código de seguridad para poder continuar...");
  else
  {
  
    status = getFileFromAJAXPOSTMethod("verify.php?id=" + Math.random(), "adcopy_response=" + document.frm.adcopy_response.value + "&adcopy_challenge=" + document.frm.adcopy_challenge.value, 10000);
    
    if(trim(status) == "")
    alert("Sin respuesta o no se encuentra el archivo en el servidor.");
  else
  {

   try
     {
                                  
       if(isNumeric(String(trim(status))) == false && isNaN(parseInt(trim(status))) == true)
         alert("Respuesta invalida del servidor.\n------------------------------------------\n" + status);
else
{
 
   switch(parseInt(trim(status)))
{

   case 0:
 
alert("Sin respuesta o no se encuentra el archivo en el servidor.");
break;
 
case 200: //OK
 
   document.getElementById("cmdAccess").disabled = false;
   alert("Captcha resuelto correctamente, presione el botón 'Acceso' para continuar.");
   
break;
 
case 400: //Incomplete message to send

alert("Datos incompletos enviados al servidor.");
break;
 
case 403: //Denied access

alert("Código de seguridad incorrecto, intente de nuevo por favor.");
break;
 
default:
 
alert("Error desconocido desde el servidor: " + status);
break;
   
   }    
 
   } 
       
     }
     catch(e)
     {
        alert("Error critico: " + e.toString());
}
    

    
  }

}

-->
</script>
</head>
<body>

<form method="post" name="frm" action="target.php" style="display: inline;">

<table border="0">
<tr>
<td valign="top">Su nombre completo:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="fullname"></td>
</tr>
<tr>
<td valign="top">Su Email:</td>
</tr>
<tr>
<td valign="top"><input type="text" maxleght="255" name="email"></td>
</tr>
<tr>
<td valign="top">Comentarios:</td>
</tr>
<tr>
<td valign="top"><textarea maxlength="255" name="comments" style="width: 100%;" rows="7"></textarea></td>
</tr>
<tr>
<td valign="top">

<!-- CAPTCHA SECTION -->

<?

 require_once("../solvemedialib.php");
 echo solvemedia_get_html("your_challenger_key");

?>

<!-- CAPTCHA SECTION -->

</td>
</tr>
<tr>
<td valign="top">

<table border="0">
<tr>
<td valign="middle"><input type="button" value="Verificar" style="height: 30px;" onclick="javascript:verify();"></td>
<td valign="middle"><input type="submit" value="Acceso" style="height: 30px;" id="cmdAccess" disabled></td>
<td valign="middle"><input type="reset" value="Borrar" style="height: 30px;"></td>
</tr>
</table>

</td>
</tr>
</table>

</form>

</body>
</html>

  Como vemos, el funcionamiento es prácticamente el mismo que en los ejemplos de securimage y quick captcha, la única diferencia es que solvemedia genera el captcha desde su servidor, en lugar de hacerlo desde el nuestro, y claro, cada script tiene un sistema de validación diferente, pero al final de cuentas lo mismo: se revisa que la palabra ingresa corresponda al texto generado en pantalla y se establece una variable a true si hubo éxito, false si no fue así, y luego con ello ya se otorga el acceso o no.

Salida de solvemedia para el método AJAX.
Solvemedia

























Este es el archivo de la verificación (verify.php)
<?

  if(isset($_POST["adcopy_response"]))
    $captcha = trim($_POST["adcopy_response"]);
  else
    $captcha = "";
    
  require_once("../solvemedialib.php");
  
  if(trim($captcha) == "")
    echo "400";
  else
  {

  $privkey="your_verify_key";
$hashkey="your_hash_key";
$solvemedia_response = solvemedia_check_answer($privkey,
$_SERVER["REMOTE_ADDR"],
$_POST["adcopy_challenge"],
$_POST["adcopy_response"],
$hashkey);

if($solvemedia_response->is_valid)
      $captcha_status = true;
  else
    $captcha_status = false;
  
  if($captcha_status == true)
      echo "200";
    else
      echo "403";
      
  }

?>

  Si hubo éxito el botón "Acceso" se habilitará y permitirá al usuario avanzar, de lo contrario solo verá un mensaje de error al presionar el botón "Verificar".

Conclusiónes:


  No es muy dificil implementar un sistema de captcha en nuestra web y librarla (en parte) de los spambots. Vimos cuatro ejemplos funcionales de sistemas de captchas, espero hallan sido de su agrado y los espero en la próxima entrega de este artículo donde vamos a implementar un sistema de captcha para nuestra web. El cual por cierto será será complemente libre, espero les sea de utilidad.

¿Te gustó este post?, entonces si lo deseas puedes apoyarnos para continuar con nuestra labor, gracias.



Licencia de Creative Commons Esta obra está bajo una licencia de Creative Commons Reconocimiento 4.0 Internacional, haga clic aquí para conocer más detalles.


Compartir:



Danos tu voto
Comunidad Kynamio
Directorio de blogs, ¡agrega el tuyo!
Programas para el mantenimiento de Windows
Blog de seguridad informatica