Inicio / Blog / Autenticación segura con passwords... ¿es posible?

Autenticación segura con passwords... ¿es posible?

Publicado el 01/07/2014, por Jesús Díaz (INCIBE)
Login box

Cada cierto tiempo hay nuevas noticias informando de ataques a servidores de compañías importantes, muchas veces resultando en leaks de contraseñas e incluso datos financieros. Por ejemplo, uno de los incidentes de más impacto en los últimos meses afectó a Adobe. Tras investigar este suceso, Paul Ducklin, estimó el número de contraseñas comprometidas en 150 millones. Otro caso reciente es el de eBay, que tras el compromiso de credenciales de algunos de sus trabajadores, fue víctima de accesos no autorizados a su base de datos de usuarios, teniendo que pedir a los mismos que cambiasen su contraseña.

También es de sobra conocido que la elección de contraseñas inseguras sigue siendo un mal hábito entre los usuarios. Por ejemplo, a partir del leak de Adobe mencionado antes, se vio que el top 100 de los passwords más comunes (y débiles) se repetía para casi 6 millones de usuarios. Ante esto último, poco se puede hacer aparte de concienciar a los usuarios sobre elegir contraseñas robustas, no reutilizarlas, y cambiarlas con determinada frecuencia. No obstante, incluso si las contraseñas son seguras, ¿existe algún método que proporcione garantías de seguridad adicionales?

Secure Remote Password: probar que sabes una contraseña sin revelarla

El protocolo SRP (Secure Remote Password) permite que un usuario demuestre el conocimiento de una contraseña, sin que en ningún momento quien la comprueba tenga conocimiento de la misma o de un valor derivado de la misma tras la aplicación de una función hash. Este mecanismo sigue siendo un gran desconocido, pese a haber sido creado en 1998 en Stanford y estandarizado como parte del protocolo TLS a través del RFC 5054.

SRP establece, entre la contraseña del usuario y un verificador con unas propiedades concretas, una relación asimétrica similar a la que existe en criptosistemas de clave pública. De esta forma, el password nunca sale del ordenador del cliente, ni siquiera cifrado o tras aplicarle una función hash. Con este protocolo, el usuario puede demostrar al servidor el conocimiento de la contraseña, pero sin revelarla. En criptografía, esto se conoce como "pruebas de conocimiento nulo" (o de conocimiento cero).

Registro

Como en cualquier sistema, los usuarios primero tienen que registrarse para establecer un nombre de usuario y contraseña. En SRP, el usuario calcula:

    • x = hash(s,pass), donde s es un valor aleatorio (utilizado como salt) y pass es la contraseña.
    • v = gx mod p, donde p es un número primo suficientemente grande (y, para los más matemáticos, g es un generador de Zp).

Para completar el registro, el usuario envía s y v al servidor. Este par (s,v) se conoce como el verificador del usuario. Estableciendo una analogía con la criptografía asimétrica, pass es la clave privada, y (s,v) la clave pública.

Autenticación

Cuando el usuario quiera demostrar al servidor que conoce la contraseña, se ejecuta el siguiente protocolo:

srp_auth_protocol

Es decir, cada vez que Alice quiera autenticarse:

  1. Calcula el valor A = ga y lo envía al servidor junto con su nombre de usuario. Como a se obtiene aleatoriamente en cada autenticación, A también será distinto en cada una de ellas.
  2. El servidor busca el par (s,v) que se registró a nombre de Alice al darse ésta de alta en el sistema, y calculará B, S y K como se especifica en el paso 3, utilizando unos valores b y u aleatorios y distintos en cada ejecución del protocolo. El salt s, junto con los valores u y B son enviados a Alice.
  3. Como Alice es la única persona que conoce x (dependiente del password), definido durante el registro inicial, sólo ella podrá derivar el elemento M tal y como se muestra en la figura. Alice envía este valor en el último mensaje, con el cual el servidor tendrá la certeza de que quien se está autenticando conoce la contraseña correcta, aún a pesar de no saber cuál es la contraseña en concreto.

El esquema anterior muestra una versión “corta” del protocolo, que también soporta autenticación básica para el servidor. Para detalles concretos sobre la versión completa, y la demostración matemática de las fórmulas anteriores, se puede consultar el artículo original.

Caso práctico: Apache con SRP

Aunque la teoría del protocolo pueda parecer compleja, vamos a ver cómo aplicarlo en la práctica de una manera muy sencilla, tomando Apache como ejemplo.

En primer lugar, el servidor debe mantener un fichero con los verificadores (el par (s,v) asociado a cada usuario). Openssl ofrece el comando srp, con el que se puede crear el fichero con la siguiente secuencia:

$ touch passwd.srpv
$ openssl srp -srpvfile passwd.srpv –userinfo "user1 info" -add user1

El comando anterior añade una nueva entrada en el fichero passwd.srpv, que incluye el nombre de usuario, el verificador, el salt utilizado al generar el verificador y los parámetros criptográficos utilizados, además de la información miscelánea asociada a dicho usuario. Una entrada en dicho fichero tiene el siguiente aspecto:

$ cat passwd.srpv
V 2vVV9tT33EzsbTwxC1OUNLl7TYu8wd1r6kMfVeJ7oMxY55C8frKtuGVxQqvxmLWkDfIOwSHy1rrw1cNlXN.o
bE1O0LyCVxCc56BzIBEgziNuxty9Hv.fKwWy8YKZQZSxQ1tFwe9RmnHJLmZi4jltrw1URkuGTWCXv6CzHoBH
UWkDhGCrmDGEWnoiA3nWnnL6FRGD5fYcTD1dbBFWbdxSaFx7rPGFB9OrVdTtddvGHmS7kNqVdX8egC.UU
b4UX15NDtKUx5HkoIGZUC3kylFGz6HZZNY7Q1NjO0wKHiTce88BQSYBe45JOPlzQrT4FbNRfQpZS1pIksiwg
UmkSRFZMNlciaE7XMEq5oejH1K6xecP4seamgmhR7e1Klm5Sw.zVY7OlizWMVCPUnZNZsOIldHK0ziRp2omQ
lhHQJYx9.3W3q15D.Az3GAu6gVFD6.8oVdt1zFfBIzIhDrKbBsAZEmWqXUcBqjmSlDVicVrWPN7mIxF2TiqsJqn
ZAeumjrnv6GKUOxsvY0iLQm35IKiaZmn6HSBodgWOZ4CeAYyWzyWhunV5zAUTum4wW1xLwcFwfELqLsT
0STWW.N6szrv8luFj0Ppz.hpR7gTWlzu81fCZ2otFyT.qiWLOhJYaVSC.bp7N5q6mJ7p1eCsTYOy.fo..mcjQeeK
lgMuHKgFDhv5MXXElPpMvcA8Jr1CC61SMdQncWkNyPkhdR2n.rE1VRvkYNlnVQ9Wbo2IwwcAjQ.0h8Aniy6x
TDVYwdQDmtIWduPVeEXOR1Bz1wtJZHtklyzhZ6hn3Ca7j.dZJlBXIEYxzA0JSiwWMb2nwP9NaChYrc3Zgz2n
MX3VjX85TONIzGuBLKlKrSSf4BMPflWs9KK6R1IRW8tJeOCBHiP01fd4PcrNOjdZub8aVes.K5AVydNe08ti83r
zZD6Mo2vbruTGSGD2CGuSlxCBA1RjY7WuI.EVI9lPuBp12j6xvrxTB7Mxrnhev0aHL8jj5hzq9ooOpQuPztO5g
KNQ98FAMpkFZNh4BE2kYdn.DTW8hy9QXk8uDoDKM1qkcLiCbbShohhlFCOgnKKKvXnVq5ZXgZuATb2kOMd
HMzKShsUvg4AZk3YDF.sJPmnxkWlbCtl6nsZ1KOzksZIlGK.MPEuQVFn2WAB7GI3YXBg5YT1dUQJiQHmP7oX
n4pT7txX0vyjjEa0DxT4RgzQXgi8ofrwLNxQVyRVfIx2SF4xVEEOPdZFBnRZWIt584OYb5ps9AtwSUGg1MOy6
blZLVklB60CG9fkPvmvxhjNhMOpTHzuUsiMSakLx8KxXu4bhmjwM1iWzvp67rl6U20QeVb4NexuL8.ywURl4P
WyPgg/SSiK5dlomLh1w/OvTHj user1 8192 user1 info

Evidentemente, lo ideal es que esta entrada la genere el usuario, y transmita los valores finales al servidor para evitar que este último obtenga la contraseña.

A continuación, en el servidor Apache habrá que especificar dónde se localiza el fichero con los verificadores. Opcionalmente, añadiendo además la segunda instrucción mostrada en el siguiente cuadro, se obliga a que los clientes se autentiquen con SRP:

SSLSRPVerifierFile /path/to/passwd.srpv
SSLCipherSuite "!DSS:!aRSA:SRP"

Para comprobar que funciona, se puede utilizar cualquiera de los siguientes comandos (en el caso de usar openssl, habrá que introducir la contraseña a continuación):

$ curl --tlsuser --tlspassword URL –k
$ openssl s_client -host -port -srpuser -srppass stdin

Una vez autenticado el usuario, Apache establece las variables SSL_SRP_USER y SSL_SRP_USERINFO, desde donde se puede acceder a la información correspondiente del usuario.

Con lo anterior, tendríamos preparado un servidor con soporte para SRP. No obstante, la principal desventaja de este protocolo de autenticación es que, al ser un método avanzado con una fuerte base matemática, requiere un respaldo aceptable por parte de los frameworks de desarrollo web y empresas importantes del sector (en forma de integración nativa en sus soluciones) para que tenga una facilidad de despliegue aceptable. En el caso de SRP, este soporte no es muy extendido, aunque por ejemplo Mozilla ya mostró interés hace tiempo.

A pesar de ello, el esquema se incluye en librerías como openssl, GnuTLS o BouncyCastle (el listado completo de librerías se puede consultar en la web de Stanford). Además, Apache lo soporta a través de mod_ssl como ya se ha visto, y JBoss proporciona el paquete org.jboss.security.srp. También existen librerías independientes en javascript y módulos específicos para frameworks como django (aunque no parece estar mantenido y configurarlo puede no ser directo) u otros frameworks, como Meteor, que lo incluye como método nativo de autenticación.