28 enero 2011

Contraseñas de un solo uso en Apache

Hace unos días hablábamos de 'Contraseñas de un solo uso en Linux' y explicábamos como configurar Linux vía PAM para aceptar contraseñas temporales. Hoy le toca el turno al servidor web mas empleado en Internet: Apache.

El objetivo de este post es configurar Apache para proteger un directorio cuyo acceso sea mediante contraseñas de un solo uso, para ello vamos a emplear mod-authn-otp, que se integra perfectamente dentro de Apache.

Una vez descargado y compilado (el típico ./configure && make && make install) procedemos a configurarlo.

Lo primero es decidir cual va a ser el directorio que vamos a proteger, en este caso será el directorio 'test' localizado físicamente en /var/www/html/test/ que a su vez se mapea vía http en www.midominio.com/test

Localizamos el fichero httpd.conf (en sistemas RedHat / CentOS / Fedora /etc/httpd/conf/httpd.conf) y añadimos lo siguiente:

#Configuracion para OTP

LoadModule authn_otp_module modules/mod_authn_otp.so

<Directory "/var/www/html/test">

    AuthType basic
    AuthName "My Protected Area"
    AuthBasicProvider OTP
    Require valid-user
    OTPAuthUsersFile /etc/httpd/otp/passwd
    OTPAuthMaxOffset 4
    OTPAuthMaxLinger 1000

</Directory>

De este punto de la configuración lo más interesante son las directivas OTPAuthUsersFile OTPAuthMaxOffset y OTPAuthMaxLinger la primera sirve para indicar donde Apache encontrará el fichero con los usuarios / tokens y PINs, para explicar la segunda y la tercera requiere meter un poco de teoría sobre HOTP, que es el algoritmo que emplea mod-authn-otp (aunque también soporta mOTP, pero no lo vamos a ver en este post). Este algoritmo basado en HMAC tiene dos formas de ser empleado, o bien como algoritmo basado en 'tiempo' (es decir, para calcular el password temporal se emplea la fecha+hora del sistema) y también en formato 'evento'.

El comportamiento basado en 'tiempo' implica que la contraseña que espera el servidor se computa tomando como elemento de la fórmula la fecha del sistema y requiere que tanto cliente como servidor estén sincronizados. En el caso de 'evento' el concepto cambia y funciona de la siguiente manera:
  1. Cliente y servidor empiezan en una situación de inicialización (número de contraseñas generadas 0)
  2. La primera vez que el cliente quiere acceder al servidor, este genera una contraseña OTP y la suministra al servidor, cuando el servidor da por buena la contraseña, aumenta en +1 el contador de contraseñas creadas
  3. La siguiente vez que el cliente accede al servidor, cuando va a generar la contraseña debe indicar que ahora ha de generar la contraseña numero 2 (la número uno ya no vale, el servidor ya NO espera esa contraseña)
  4. Y así sucesivamente
Por tanto para emplear este modo requiere 'llevar la cuenta' de cual contraseña se ha de crear. Si existe un desfase entre las contraseñas que has creado y las que has enviado al servidor se puede romper la sincronización.

Explicado esto volvemos a la directriz OTPAuthMaxOffset que define el número de contraseñas de 'desfase' que va a calcular el servidor, es decir el servidor te ofrece de margen hasta 4 contraseñas (si el servidor espera la contraseña número 2 y tu envías la número 4, podrás acceder ya que cae dentro del margen)

En el caso de la directriz OTPAuthMaxLinger especifica el tiempo máximo en segundos que puede permanecer el cliente conectado al recurso del servidor sin necesidad de generar otra nueva contraseña. En función de 'que' estamos protegiendo debemos calcular este parámetro, ya que si esperamos que el cliente esté conectado mucho tiempo puede ser realmente molesto estar cada 2 x 3 calculando contraseñas si ponemos una ventana de tiempo pequeña.

Ahora vamos a explicar como crear el fichero con los usuarios / contraseñas. Mi elección para la ubicación de este fichero es /etc/httpd/otp/passwd pero puede ser cualquier otra. Creamos el fichero:

# mkdir -p /etc/httpd/otp/
# touch /etc/httpd/otp/passwd
# chown -R apache.apache /etc/httpd/otp/

A la hora de crear este fichero, echo mucho mucho en falta algún tipo de herramienta que debería formar parte de mod-authn-otp (y la documentación no es para nada evidente). El formato del fichero es el siguiente:

HOTP    sbdtest       1234    167aa8035341c4e812adce9c26a9f71c

En este caso vamos a usar auth HOTP por eventos (sin sincronización de tiempo) El primer campo es el tipo de auth que vamos a usar, el segundo el username, el tercero es el PIN y el cuarto el token/key.

Teóricamente la parte mas problemática es el token (que, según leo en la documentación, es una representación hexadecimal de un dato aleatorio binario), si usas uno de los soft tokens que recomiendan en el proyecto (hay clientes para Iphone y para Android) el token lo auto-genera el software. Como en este caso queremos usarlo utilizando la herramienta para generar OTPs de mod_authn_otp (otptool) tenemos que crear la parte del token 'a mano'.

Probablemente haya métodos mas fáciles, pero yo lo he hecho así;

Primero generamos un montón de datos binarios aleatorios y los volcamos en el fichero 'random':

# dd if=/dev/urandom of=random count=1

Luego sacamos la representación hexadecimal del fichero:

# hexdump random

Lo que nos dará una salida como:

0000000 003c 19f5 32d8 b89d c982 c854 9471 be51
0000010 b0d2 1fd7 7ddc 7612 4b85 1665 8a47 43b1
0000020 8122 12f3 3f36 5dca 4b3a 751b c0cd 97eb
0000030 12d8 01c8 2860 4176 d637 27f4 f554 61d1
0000040 6056 fd89 055f e72c 0882 0698 4797 2b21
0000050 7532 f86a 3786 1221 d28d e8dd 57c2 30c3

de ahí seleccionamos una fila, por ejemplo:

003c19f532d8b89dc982c8549471be51

Y ya tenemos nuestro token !

Por tanto podemos crear al usuario sbdtest de la siguiente forma

HOTP    sbdtest       1234    003c19f532d8b89dc982c8549471be51

En este caso el PIN es 1234 y el token, lo que anteriormente generamos. Con todo esto re-iniciamos el servidor httpd y empleando la herramienta otptool (que se compila e instala junto con mod_authn_otp), generamos nuestro primer password temporal tomando como parámetro el token:

# otptool 003c19f532d8b89dc982c8549471be51
0: 944668 61a95c

De aquí, nos quedamos con 61a95c, apuntamos nuestro navegador hacia el directorio protegido www.midominio.com/test y debería pedirnos login y password, como login --> sbdtest y como password el PIN+OTP, es decir 123461a95c

Et voila ! deberíamos haber accedido al recurso protegido

La siguiente vez que queramos acceder debemos indicar a otptool que ha de generar la siguiente contraseña con el parámetro -c 1, la siguiente vez será -c 2 y así sucesivamente:

# otptool -c 1 003c19f532d8b89dc982c8549471be51
1: 044536 8202f8

Un último apunte, como decía al principio existen soft-tokens para Iphone y Android aquí

6 comments :

vierito5 dijo...

Interesante, no conocía la existencia de este módulo. A ver si tengo tiempo y me miro las interioridades.

Jandro dijo...

+1

peluzza dijo...

Interesantísimo! Me encantaría saber si el concepto OTP es posible ser usado para login de sesión para los distintos sistemas operativos y en servidores de correo electrónico particulares.

Podrían suponer el final del phishing.

Sergio Hernando dijo...

Me viene de perlas para un servidor casero. Excelente trabajo :)

Antonio Navarro Navarro dijo...

Si, el concepto de OTP tanto con software como con dispositivos hardware (ideal porque no puede duplicarse) es aplicable a todos los entornos en los que se necesita autenticación de dos factores con claves de un solo uso. Podéis ver más detalles en autenticación OTP, un artículo de mi blog.

Pablo dijo...

Como hago que el contador crezca despues de cada login me refiero a que no aumenta en +1 el contador de contraseñas creadas... tienen idea de porque puede ser?? muy bueno el post!! la verdad te pasaste