Hola a todos,
No sé si ya se ha hablado de esto aquí anteriormente, pero para desempolvar un poco la bodega pongo a su disposición un mecanismo para que puedan implementar la
autenticación de dos factores en sus sitios
web.
Para quienes desconozcan el asunto, resumo que ésta consiste en proporcionar un código de seguridad (generalmente de seis dígitos) además de los consabidos nombre de usuario y contraseña. El ejemplo, quizá más conocido es el de GMail. Cuando activamos la autenticación de dos factores y queremos ingresar a nuestra cuenta desde un dispositivo desconocido, Google nos requerirá, luego del usuario y contraseña, de un segundo paso (factor) para comprobar que realmente somos quienes decimos ser y no alguien que se robó nuestro
username y
password. Si nuestra cuenta de correo está asociada ya a nuestro móvil, el segundo factor puede ser simplemente el oprimir el botón "SÍ" que nos llega al dispositivo.
Pero también podemos hacer uso de un generador de códigos como el
Google Authenticator del propio Google o cualquier otro como
el de LastPass. Estos códigos corresponden al concepto de
One Time Password, es decir, contraseñas de un sólo uso, que es precisamente lo que aumenta la seguridad de nuestra cuenta. Huelga decir que para hacer uso de esta funcionalidad, GMail nos pide primero dar de alta la cuenta en el autenticador. El código proporcionado por el autenticador tiene un tiempo de vida de 30 segundos.
Este código de seis dígitos:
se asocia a un servicio y usuario específicos, por lo que, como se ve en la imagen, distintas cuentas proporcionan distintos códigos.
Pues bien, la idea entonces es poder usar cualquiera de estos autenticadores en nuestras propias aplicaciones web.
A
grosso modo a cada usuario de nuestro sistema se le proporciona un código numérico y un código QR:
que se escanea con el autenticador para dar de alta la cuenta o, si uno es masoquista, captura el código de 64 caracteres.
Cuando el usuario desee ingresar a nuestra aplicación, podemos pedirle, luego de su usuario y contraseña, el código de seis dígitos que en ese momento aparezca en el autenticador y que nosotros comprobaremos. Podemos hacer eso porque el código se genera básicamente con dos elementos:
- El Unix Timestamp actual (o mejor dicho, el intervalo de 30 segundos más cercano) y
- una llave secreta que conocemos nosotros y que se le pasa al autenticador al momento de escanear el código QR (por lo cual el código QR debe poseerlo únicamente el usuario calificado).
La llave secreta que se pasa al autenticador debería ser una combinación de una llave conocida sólo por nosotros y el nombre de usuario para que cada usuario reciba códigos de segundo factor distintos.
Para que el usuario reciba su QR sin riesgo a que revele a otros nuestra llave, ésta debe combinarse con su nombre de usuario de una forma no trivial, por ejemplo, usando la función hash_hmac de PHP:
Código PHP:
$llave = hash_hmac('sha1', 'tribilin', "Mi súper llave secreta compartida");
Para que el autenticador acepta la llave, debemos codificarla en base 32, lo que nos dará justamente:
Código:
MZRDIZRQGI4TIYZTMY2WGMZRMQ4DQODDG43TKNRVGZTGIZRUMUYTCMRUMQ4TCNBW
como se muestra en la imagen.
Si se decodifica eso, sólo se verá:
Código:
fb4f0294c3f5c31d888c775656fdf4e1124d9146
que no revela la súper llave secreta.
En el archivo adjunto viene una carpeta
oath con el código fuente de un ejemplo de verificación del segundo paso y la generación del código QR (usando el servicio de Google API Chart). Si disponen de un servidor local de desarrollo, deberían poder colocar la carpeta en su raíz web
escribir un nombre de usuario y escanear el código con el autenticador. A partir de entonces, en el segundo recuadro colocan el código del autenticador y presionan SEND para verificar.
Los archivos que dan vida a esto vienen en la carpeta oath/src y son tres:
- oauth.php
- gauth.php
- base32.php
Además viene el archivo hmac_sha1.php que no es necesario pero que les puede servir para ver cómo se implementa el hash_hmac que mencioné arriba.
El archivo oauth.php tiene varias funciones, pero la básica es
totp (de
Time based
One
Time
Password). Esta función recibe como parámetro único la llave tal como se le envía al autenticador, ANTES de codificarla en base 32, y devuelve el código de seis dígitos que es el que compararíamos con el que nos proporcione el usuario en el segundo paso de la autenticación.
En el archivo gauth.php contiene la función gauth cuyos parámetros principales son:
- $user nombre de usuario de la aplicación
- $key La llave secreta que se le pasó al autenticador (sin codificar en BASE 32)
- $issuer Nombre de la organización que emite la llave (lo escogemos nosotros)
Esta función devuelve un arreglo con dos valores:
- src La url de la API Chart de Google que pondríamos en el atributo src de una etiqueta <img>
- secret La llave secreta tal como se le pasa al autenticador (ya codificada en base 32)
El archivo base32.php contiene una versión
light de codificación base 32 (es decir,
light porque es apta sólo para textos relativamente pequeños). Hasta donde he visto, PHP no cuenta con funciones para este tipo de codificación.
Como es justo
dar al César lo que es del César, menciono que la versión original de estas funciones las vi en
https://github.com/Voronenko/PHPOTP pero decidí simplificarlas en el proceso de tratar de entender qué es lo que hacían.
Desde luego, no es necesario usar el servicio de Google para generar los QR. En el archivo gauth.php está la función getOtpAuthUrl que devuelve la cadena con la que debe conformarse el QR y podemos usar cualquier biblioteca que deseemos para tal efecto.
// Saludos