AntiSpam: Captcha accesible 17 Junio, 2007
Esta entrada ha sido publicada por Covi y está archivada en Desarrollo Web
Retomando el tema del SPAM (en Foros del Web por ejemplo) y las ideas que tenía sobre un “captcha” válido, accesible y útil, por fin decidí montar el sistema que pensé hace tiempo:
AntiSPAM Confirmación Visual Accesible
…me aventuraría a denominarlo “Ingeniería Social” contra bots.
El método elegido ha sido una imagen aleatoria de una de las Nuevas Siete Maravillas del Mundo Moderno.
Se puede ver el ejemplo implementado en el sitio de La Guardia que administro:
http://www.laguardiadejaen.com/web/wp-login.php?action=register
Aquí el código del sistema, aunque pretendo hacer un plugin (que quizá sea más un “hack” ya que hay que editar el archivo wp-login.php) para Wordpress.
Accesibilidad:
Viendo después algunas cosas en alzado.org decidí incluir un enlace “aclaratorio” -y un esfuerzo extra para el usuario
- de orientación pensando también en la lógica humana, esto es trasladable al tema de accesibilidad, es decir:
- Si alguién no puede ver la imagen debe haber una alternativa.
- Si alguién no conoce o no entiende la imagen debe haber una alternativa.
- Ambas deben ser algo complicadas para un bot.
Así, en relación a la accesibilidad se concluye que necesito:
- Un enlace a una página algo descriptiva y orientativa: El artículo de la Wikipedia.
- Y el lapidario atributo alternativo de imagen (alt), que para eso está, con una descripción de la imagen pero que no es el valor exacto a incluir en el campo.
El Sistema:
Bien, necesitamos trabajar con dos archivos básicamente y un directorio:
- Creamos un archivo:
wp-captcha.php - Editamos el archivo en la raíz de wordpress:
wp-login.php - Creamos un directorio: 7maravillas con las imagenes del artículo de la Wikipedia.
Notas:
El sistema es altamente configurable, desde wp-captcha.php:
El captcha a usar, con imágenes y monumentos, personajes famosos… etc, a cálculos matemáticos por imagen… el límite lo pone tu imaginación.
El sistema de presentación de la imagen.
Las extensión de las imágenes.
ACTUALIZADO: Leyendo más sobre captcha, y habiendo obtenido hasta la fecha un resultado 100% satisfactorio -ni un solo bot registrado-, acabo de pensar en una posible vulnerabilidad más solucionada en parte creo gracias al cifrado.
Es algo tan básico… que me averguenza un poco no haberlo pensado ![]()
CIFRADO DEL DATO DE SESIÓN.
El potencial sobre los requisitos del registro está en la edición del wp-login.php:
Pasos:
1. Creamos el archivo wp-captcha.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | <?php /* Importante: Por favor, para usar este codigo MANTEN el texto y la licencia siguientes: -------------------------------------------------------------------------------- 7 Maravillas AntiSpam Copyright 2007 Juan Antonio Cobo Ruz (email : juanancobo@gmail.com) * License GNU General Public License (GPL) ** http://www.gnu.org/licenses/licenses.html#GPL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA --------------------------------------------------------------------------------* */ // Datos: $ext_imagen = "jpg"; $captcha_dir = "7maravillas/"; // Array con las imagenes en el directorio. $imagenes = array( '0'=>array('name'=>'alhambra','alt'=>'Alhambra de Granada, Granada, España'), '1'=>array('name'=>'machu picchu','alt'=>'Machu Picchu, Cusco, Peru'), '2'=>array('name'=>'angkor','alt'=>'Angkor, Siem Reap, Camboya'), '3'=>array('name'=>'cristo redentor','alt'=>'Cristo Redentor, Río de Janeiro, Brasil'), '4'=>array('name'=>'coliseo','alt'=>'Coliseo, Roma, Italia'), '5'=>array('name'=>'torre eiffel','alt'=>'Torre Eiffel, París, Francia'), '6'=>array('name'=>'petra','alt'=>'Ciudad de Petra, Jordania'), '7'=>array('name'=>'piramides de gizeh','alt'=>'Pirámides de Gizeh, Egipto'), '8'=>array('name'=>'estatua de la libertad','alt'=>'Estatua de la Libertad, Nueva York, Estados Unidos'), '9'=>array('name'=>'stonehenge','alt'=>'Stonehenge, Amesbury, Reino Unido'), ); // Seleccion aleatoria imagen. $aleatoria=rand(0,count($imagenes)-1); // Alt de la imagen aleatoria $alt_imagen = $imagenes[$aleatoria]['alt']; // Nombre a enviar de la imagen: $name_imagen = $imagenes[$aleatoria]['name']; // Sesion y establecemos el nombre: session_start(); $_SESSION['maravilla'] = md5($name_imagen); // Opcional: // NO ES RECOMENDABLE USAR ESTE CSS INCRUSTADO, mejor usar reglas en tu plantilla CSS: echo '<p style="font-size:10px;text-align:center;"><strong>Maravillas del Mundo Moderno</strong><br /> Pulsa <a href="http://es.wikipedia.org/wiki/Nuevas_Siete_Maravillas_del_Mundo" title="Wikipedia#Maravillas del Mundo Moderno" style="color:#fff;"> <strong>aquí</strong></a> si no sabes el nombre exacto.<br />'; // Requerido, muestra la imagen aleatoria: echo '<img src="' . $captcha_dir . $aleatoria. '.' . $ext_imagen . '" alt="Si no puedes ver la imagen, en el siguiente texto mostramos qué monumento es: '.$alt_imagen.'" style="padding:2px;border:1px solid #ccc;text-align:center;" /></p>'; ?> |
Lo que hemos hecho ha sido:
- Establecer la extensión predeterminada de los archivos.
- Establecer el directorio de las imágenes.
- Crear una matriz asociativa con los nombres de los archivos de imagen con índice numérico: 0, 1, 2 para crear la presentación aleatoria numéricamente (más fácil).
- Establecemos el nombre del archivo de imagen aleatoriamente de entre el número de imágenes de nuestro directorio.
- Una vez lo tenemos: Sacamos el nombre del array asociativo y sacamos el texto descriptivo para el atributo alt (accesibilidad).
- Guardar el nombre que le hemos dado a la imagen, NO el nombre del archivo sino el nombre QUE LE HEMOS DADO a la imagen en la matriz, en una variable de sesión para comprobar que se corresponde con el dato introducido en el formulario.
- Ciframos el dato de sesión
- Mostramos la imagen
2.Editamos el archivo wp-login.php:
Alrededor de la línea 10:
Desactivamos la función de Wordpress para las cabeceras (si no tiraría un error de cabeceras enviadas al iniciar la sesión).
9 10 11 12 | /* Mod by Covi */ //nocache_headers(); session_start(); /* end Mod by Covi */ |
Buscamos la opción de Registro: case 'register' : de la sentencia switch:
Y antes (da un poco igual porque se comprobarán todos los campos) de que compruebe el nick (if ( $user_login == '' )) introducido en el formulario, realizamos nuestra comprobación personal del valor del nombre de la imagen, en este caso de una de las Nuevas Maravillas del Mundo Moderno… (usaremos el mismo mensaje de error para todo):
Alrededor de la línea 229 tras añadir el código anterior, añadimos:
229 230 231 232 233 234 | /* Mod by covi */ // Comprobamos la maravilla if ( $_SESSION['maravilla'] != md5(strtolower($_POST['maravilla_send'])) ) $errors['user_email'] = '<strong>ERROR</strong>: El nombre de la maravilla no es ese.'; //end comprobacion /* end Mod by Covi */ |
También hemos guardado y pasado el nombre de la Maravilla a minúsculas para no ser demasiado estricto y lo más importante, mandamos el valor encriptado con md5 que es como se encriptó el dato de sesión $_SESSION['maravilla'] = md5($name_imagen);.
3. Solo nos quedaría, en este archivo (wp-login), incluir el campo del formulario y la imagen aleatoria:
Un buen lugar por ejemplo sería después del campo de email y antes de la función que comprueba el formulario.
Buscamos una de las instrucciones siguientes (puede variar dependiendo de la versión de Wordpress).
_e('A password will be e-mailed to you.')
do_action('register_form');
Y añadimos dejándolo algo así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <p id="reg_passmail"><?php _e('A password will be e-mailed to you.') ?></p> <?php /* Mod by Covi */ ?> <!-- Comprobacion de la maravilla --> <?php /* Inlcuimos la imagen y los datos de sesion: */ require_once( dirname(__FILE__) . '/wp-captcha.php'); //DEBUG: print_r($_SESSION); ?> <p><label for="code">Por favor, introduce aquí el <strong>Nombre</strong> (tal cual, sin acentos) <strong>de la Maravilla</strong> de la imagen anterior:</label> <input class="input" name="maravilla_send" id="maravilla_send" type="text" size="20" value="" /></p> <!-- end Comprobacion de la maravilla --> <?php /* end Mod by Covi */ ?> <?php do_action('register_form'); ?> |
Crear el directorio de imágenes:
Fácil, quizá solo recordar que este método de imagen aleatoria se realiza de modo numérico, más rápido y fácil, y por lo tanto los nombres de las imágenes deberían ser numéricos también: 0.jpg, 1.jpg…
Podríamos hacer algo más sofisticado con un script que leyera los archivos del directorio (con los añadidos de seguridad, de carga de servidor… que eso ya conlleva) y generara igualmente una imagen aleatoria, podríamos crear otra matriz (array) para las extensiones de archivo permitido, etc, etc…
Mejoras
Las mejoras a incluir podrían ser varias pero entre algunas que pensé serían:
*Un mejor cifrado (más que md5) del nombre de imagen a través de una “semilla” por ejemplo.
*Usar JavaScript para volver a evitar bots, si se tiene desactivado se ofrece una opción accesible pero antibots, es decir, que requiera la comprensión humana.
*Se me acaban de olvidar las más importantes
…., no puede ser
ggg ![]()





[...] Lo mantengo inactivo para urgencias, ya no es necesario con el sistema AntiSpam. [...]
27 Septiembre 2007 @ 18:26
Me parece muy interesante este tipo de captcha, pero…¿¿¿estará el personal, con el nivel cultural suficiente para saber el nombre de las “nuevas maravillas del mundo”???
5 Abril 2008 @ 22:37
Ya hemos comentado este tema varias veces…
Creo que pone bien claro:
“Pulsa aquí si no sabes el nombre de la maravilla”.
Y en la entrada…. es que lo cito explícitamente:
No es tan sencillo como preguntar 2+2 pero tampoco es para ser ingeniero técnico en nada
y como digo, sí se lee…. un poco, que es lo mínimo que se hace en una web, se puede saber perfectamente el nombre.
Además, para alguien más experto en HTML, solo tiene que leer el fuente o las propiedades de la imagen, algo por otra parte que beneficia la accesibilidad, pues el nombre se desvela en los atributos accesibles, pero que perjudica en temática spam pues un robot adiestrado para ello podría sacarlo fácil.
—
Aún así… el capta está desactivado por el momento (y el spam, ahora mismo, me come, claro).
Pero no voy a usar opciones que aborrezco, literalmente, como el popular ReCaptcha.
También barajé la posibilidad de un random de imágenes más amplio y renovarlas periódicamente a la vez que entre varios sistemas tan sencillos como una simple suma o pregunta de interés general.
…pero vamos, es lo mismo de siempre: En mi opinión, las técnicas antispam dependen más de la habilidad del que diseña el sistema que de las propias herramientas en sí, así que elegir uno u otro, varios o todos a la vez, depende de eso y de las características del sistema.
Y para finalizar… el spam se ha controlado tanto en sistemas como Wordpress (Akismet por ejemplo) que es bastante difícil ya encontrar spam por comentarios, el spam usa hace días el sistema de pingbacks, algo pendiente como, en general, un buen repaso a todo mi blog

Porque es que lo tengo muy muy descuidao.
Un ejemplo: Siento el retraso en la publicación del comentario Lour
7 Abril 2008 @ 3:16