Autenticación segura sin SSL/TLS
Damián Sábado 12 de junio del 2010
Muchas veces no es necesario o es demasiado cifrar toda la comunicación entre el cliente y el servidor, por razones de performance o por el sobrecosto de implementar un esquema de PKI (Public Key Infraestructure) para usar SSL/TLS. Pero siempre hay algo que es necesario proteger por seguridad: las credenciales de autenticación del usuario. Por lo que en este post explicaré cómo se puede hacer una autenticación sin enviar esa información (no, no es telepatía).
Protocolos de conocimiento cero (ZKP)
Sabemos que sin un esquema de cifrado de llave pública es trivial para un atacante interceptar la información que se envía entre el cliente y el servidor, pero el sistema debe tener alguna manera de autenticar a los usuarios del sistema. Necesitamos enviar algo que si un atacante intercepta no pueda utilizar para autenticarse. Esto se conoce como un protocolo de conocimiento cero (Zero-knowledge proof), y en palabras coloquiales significa: “probar que poseemos cierta información sin revelar esa información”.
Como comúnmente la única información que queremos “probar que poseemos pero no queremos revelar” es la contraseña, voy a explicar el esquema que usa MySQL para implementar su autenticación de usuarios. Los detalles no están explicados de manera formal en la documentación de MySQL pero alguien se tomó el tiempo de leer el código fuente y explicar cómo funciona (MySQL 4.1.x authentication internals).
¿Cómo se almacenan las contraseñas?
Lo primero que hay que tener en cuenta es que, siguiendo los principios básicos de almacenamiento seguro de contraseñas, éstas se almacenan en el sistema sólo como un hash criptográfico. Que tiene la propiedad de ser prácticamente irreversible y prácticamente único. Por lo que esta es la primera parte del ZKP, ya que sólo quien conozca la contraseña podrá generar el hash criptográfico que le pertenece.
Desde MySQL 4.1 las contraseñas de usuario están almacenadas en la tabla “mysql.user” en la columna “Password” de la siguiente manera: . Donde
es el hash criptográfico SHA-1.
La transmisión
Si cada vez que el cliente se quiera autenticar sólo transmitiera , cumpliría con el principio de no revelar la contraseña, pero un atacante podría capturar y enviar después
para autenticarse exitosamente aún sin conocer la contraseña. Por lo que necesitamos agregar más cosas al protocolo para que la información que transmite el cliente sólo sea útil para un intento de autenticación.
Este sería el esquema cliente-servidor para la transmisión:
- Se inicia el intento de autenticación
- El servidor genera una cadena aleatoria
y se la transmite al cliente.
- El cliente calcula
,
y
(aqui
significa concatenación).
- Finalmente el cliente transmite
. (aquí
significa bitwise XOR)
Autenticación
El servidor sólo conoce , que está almacenado en la tabla de usuarios, y
. Para autenticar hace lo siguiente:
- Calcula
.
- Calcula
.
- Calcula
.
- Sólo si
la autenticación es exitosa.
Observaciones
Nunca se transmite ni
, por lo que la fortaleza está en que este ZKP verifica que el cliente conoce
y
pero sin revelar esa información, y que sería casi imposible que un atacante poseyera sin conocer
.
También hay que observar que es una cadena única por cada intento de autenticación, o sea que esa cadena siempre está cambiando.
Implementación
Próximamente trabajaremos en una implementación de este esquema para aplicaciones web usando JavaScript y PHP, que publicaremos bajo licencia LGPL.






