| Skriptke.ltn.net/hv/ | Human Verification Perl Script - Captcha script en Perl |
Download:
Versión 0.1 hv.01.gz
(Licencia GNU/GPL)¿Qué es y para qué sirve?
Es un script en Perl que dificulta que los robots rellenen formularios (Captcha). Sistema similar al que se emplea en los registros de usuarios de correo Web gratuito, y en los formularios de login para impedir el acceso a robots que intentan robar contraseñas. También se usa en registros de foros, libros de visita, etc. para impedir el acceso a robots de spam. Ejemplo:
¿En qué se basa?
El sistema está basado en que el ojo humano es capaz de ver mejor que un OCR (Optical Character Recognition / Reconocimiento óptico de caracteres). La imagen que se muestra se distorsiona hasta el punto que el ojo humano pueda verla y un OCR no.
Encontrar el punto de compromiso donde un humano puede ver la imagen y un ORC no, es complicado, aun así, en el futuro muy posiblemente los OCR sean capaces de ver tan bien o mejor que el ojo humano. Por lo tanto el sistema no es 100% seguro, sin embargo la cantidad de recursos y tiempo que un robot debe emplear para decodificar la imagen hace el sistema suficientemente eficaz. Para proteger un libro de visitas es más que suficiente, otra cosa sería el acceso a la Web de un banco, tal vez en este último caso los recursos y tiempo empleados por el robot compensen.
Un método alternativo más seguro es el que requiere interpretación, de lo que están más lejos las maquinas que de un simple reconocimiento óptico. Por ejemplo podíamos mostrar la imagen de un gato y preguntar al usuario de que animal se trata. Podemos configurar el script para una aproximación de este sistema:
Ejemplo: ![]()
Puedes ver un ejemplo real en amigar¿Cómo funciona?
El script genera una imagen junto a un identificador de sesión y un valor hash md5. El script que recibe el POST/GET comprueba el código y las variables que genera el script:
Ejemplo:
En el formulario:
<form method="POST" action="test.cgi">
Usuario: <input type="text" name="user" size="14">
Contaseña: <input type="password" name="pass" size="14"> <br>
Código de seguridad: <input type="text" name="code" size="6">
igual a: <script src="http://skriptke.ltn.net/hv/demo3/hv.cgi?4"></script>
<input type="submit" value="Ok">
</form>Hemos añadido la línea:
<script src="http://skriptke.ltn.net/hv/demo3/hv.cgi?4"></script>
Que muestra la imagen con 4 dígitos. Además al cargar el script se generarán automáticamente, visibles sólo en tiempo de ejecución, las siguientes:
<input type="Hidden" name="hv_hash" value="VALORhv_hash">
<input type="Hidden" name="hv_sess" value="VALORhv_sess">
Que definen las variables hv_hash y hv_sess que deberán ser comprobadas en test.cgi
Al script se le puede llamar para que muestre un número determinado de dígitos, hv.cgi?6 mostrará la imagen con seis dígitos, sin parámetros muestra un número aleatorio de entre 4 y 6 dígitos.
En test.cgi:
...
use CGI;
$q = new CGI;
use Digest::MD5 qw(md5_hex);
my $skey = 'ChangeIt'; # secret key
my $code = $q->param('code'); # user put code
my $session = $q->param('hv_sess');
my $hash = $q->param('hv_hash');
my $expire = 60*2; # seconds expire session
if (time - $session > $expire) {
print "Location: http://skriptke.ltn.net/hv/error_expire.es.htm\n\n";
exit;
}
if ($hash ne md5_hex($code,$skey,$session) ) {
print "Location: http://skriptke.ltn.net/hv/error.es.htm\n\n";
exit;
}
print "Location: http://skriptke.ltn.net/hv/ok.es.htm\n\n";
...La línea "$q = new CGI" recoge en la variable $q los valores pasados desde el formulario, en casos particulares tal vez se use un método alternativo al modulo CGI para recoger los parámetros.
$skey contiene la clave privada, este valor debe ser el mismo en en la configuración de hv.cgi.
$code contiene el código de seguridad tecleado por el usuario.
$session contiene el valor de hv_sess que es el valor de la función "time" cuando se ejecutó el script que genera la imagen.
$hash contiene el valor de hv_hash.
Hemos definido la variable $expire con un valor de 120 segundos, que será nuestra primera comprobación en la línea "if (time - $session > $expire)" De esta forma evitamos que una clave pueda ser usada indefinidamente. Se puede configurar esta variable según las necesidades, si el formulario es largo, no cave esperar que el usuario sólo tarde 2 minutos en rellenarlo.
Por último comprobamos que el código de seguridad es correcto con la línea "if ($hash ne md5_hex($code,$skey,$session) )" los parámetros de la función "md5_hex" deben ser los mismos y en el mismo orden que en hv.cgi.
En este ejemplo, el formulario sería el equivalente al formulario donde se quisiera implementar la utilidad, y test.cgi el equivalente al script a proteger, libro de visitas, registro de usuarios, login, etc.
Instalación
...
Se puede cambiar, si es necesario, la extensión del script hv.cgi por hv.pl, haciendo los cambio pertinentes en la variable $cgi_url de la configuración.
Configuración
El script "hv.cgi" contiene una sección etiquetada como "-- CONFIGURATION --" con las siguientes variables:
- $skey
Es la clave privada que se va usar, se deberá usar la misma posteriormente en los scripts que hagan uso de esta utilidad. Este valor es lo primero que debería cambiarse, y desde luego no usar nunca la que viene por defecto "ChangeIt"- $tmp_dir
Directorio para los archivos temporales. El script genera archivos temporales que conviene tener separados para poder eliminar posteriormente, por defecto viene configurada con el valor './tmp'.- $img_dir
El directorio que contiene las imágenes. Cada directorio contiene las imágenes para cada tipo de dígitos en formato BMP, cada archivo contiene el digito a mostrar (0.bmp, 1.bmp, 2.bmp ...) De esta forma es posible añadir más tipos y una mayor personalización. Para crear imágenes personalizadas, con un editor gráfico se crea cada dígito, añadiéndole un filtro, desenfoque, manchas, etc. para distorsionar la imagen y se guardan en formato BMP. Hay que tener en cuenta las siguientes limitaciones; sólo se admite el formato BMP, deben tener 8 bit de color (256 colores o tonos de gris), la paleta de color debe ser la misma para cada grupo de 10 dígitos, el ancho de la imagen puede ser variable en cada dígito pero el alto ha de ser siempre el mismo. Como ejemplo se pueden ver las imágenes que vienen con la utilidad.- $top_url
Dirección URL sin path donde se mostrará el script. Es usada para generar los tag HTML de las imágenes y para comprobar el refering, motivo por el cual conviene no incluir el path. No tiene valor por defecto y si no se le da un valor correcto no funcionará el script.- $cgi_url
Path (camino) del script. Es el camino donde se instala el script, por ejemplo /cgi-bin/. No tiene valor por defecto y si no se le da un valor correcto no funcionará el script.- $referrer
Si comprueba o no el referrer. Se puede comprobar el referrer para por ejemplo para evitar que se carguen las imágenes desde dominios distintos, y como medida adicional de seguridad, sin embargo me atrevo a decir que es de "dudosa utilidad". Por defecto viene con valor 0 que no comprueba el referrer.- $max_age
Tiempo máximo de vida en caché de las imágenes en segundos. Ver nota.- $max_digits
Número máximo de dígitos que se muestran. El número de dígitos mostrados se pasa como parámetro en la URL del script, con un máximo evitamos que alguien pueda cargar el script con... por ejemplo... ¿un millón de dígitos? ¿más! :-) Por defecto viene configurado a un máximo de 12.- $clear_tmp
Si borra o no los archivos temporales. Aunque el script borra los archivos temporales que crea, en determinados casos no es así, por lo que se pueden acumular archivos con el tiempo. Por defecto viene con el valor 1 que borra los archivos temporales periódicamente (según el valor de clear_rnd).- $clear_rnd
Cada cuanto borra los archivos temporales, según "1 > rand $clear_rnd". Cuando el script muestra una imagen puede comprobar si existen archivos temporales y borrarlos en su caso. Hacer esto cada vez que se ejecuta es una carga innecesaria. El valor por defecto es de 200 que según "1 > rand $clear_rnd" sería aproximadamente una vez cada 200 imágenes mostradas.- $noise
Porcentaje de ruido para añadir a la imagen. Aunque el ruido también ayuda a evitar que las imágenes puedan ser leídas por un ORC, la función principal de esta variable no es esa, sino evitar que siempre tengan la misma secuencia de bits, que de ser así no sería necesario siquiera un ORC para identificarlas. NO se recomienda en ningún caso un valor menor de 10. Lo ideal es añadir el máximo de ruido sin llegar a distorsionar totalmente la imagen, se pueden probar distintos valores para encontrar uno de compromiso. (En los ejemplos de esta página se usan valores entre 18 y 25), tampoco sería mala idea utilizar algo así: $noise = 20 + int rand 10
Existen problemas (como no) con los caché, en algunas pruebas los resultados han sido pintorescos y caprichosos, dependiendo del navegador utilizado. Pese a que a simple vista pueda ser evidente no usar caché en una utilidad como esta, en este caso parece mejor idea hacer uso de el (nos referimos al caché del navegador, no a otro tipo de proxys, transparentes, etc. que suelen dar más problemas aún, la configuración del caché es "Private" lo que en teoría evita por defecto este tipo de proxys). Existen dos posibilidades, una que el navegador hace caso omiso de nuestra configuración de caché, y dos el navegador la respeta. En el primer caso no podemos hacer nada, sea cual sea nuestra configuración obtendremos resultados imprevisibles, no referimos al segundo caso. Para entender mejor el problema conviene saber como funciona este script, la utilidad en un primer paso genera contenido "JavaScript":
La llamada:
<script language="JavaScript" src="http://skriptke.ltn.net/hv/hv.cgi"></script>
Genera el código JavaScript:
document.write('<input type="Hidden" name="hv_hash" value="6eea498acabba9e41a7383cbf2d5abbd"><input type="Hidden" name="hv_sess" value="1081021782"><img border="0" align="absmiddle" src="http://skriptke.ltn.net/hv/hv.cgi?0-6eea498acabba9e41a7383cbf2d5abbd">');
En el segundo paso el navegador ejecuta el JavaScript y muestra la imagen (http://skriptke.ltn.net/hv/hv.cgi?0-6eea498acabba9e41a7383cbf2d5abbd). Pues bien, en la mayoría de las pruebas el navegador ha mantenido en caché el JavaScript y la imagen no, con la consiguiente inconsistencia de datos, dado que los valores de los parámetros del formulario ya no correspondía a la imagen. (La utilidad impide que una misma imagen pueda ser cargada dos veces sin generar una nueva hash, por ejemplo, si se hace reload sobre la URL de la imagen da un error).Por lo tanto si se observan problemas de este tipo, hay que incrementar el valor de la variable $max_age hasta el máximo del valor que se utilice en el propio script en la variable $expire como en el ejemplo de más arriba.
|
|
... |
|
|
LTN |
|
|
... |
|