La autentificación múltiple (o de múltiples factores), estrictamente hablando, sencillamente radica en aplicar dos o más sistemas de autentificación contra un mismo servicio, y además, generalmente, aplicados deforma descendente… es decir, que son (o pueden ser) requeridos una vez el primer sistema de autentificación es validado.

Originariamente era más habitual hablar de Autentificación de dos factores, doble autentificación o sencillamente 2FA (Two Factor Authentication). Con el avance en seguridad que ha ido aconteciendo en los últimos años, aunque aun se habla casi siempre de 2FA, el término genérico ha pasado a ser Autentificación Múltiple (MFA a partir de ahora), donde podrían concurrir 2 o más sistemas de autentificación, o combinación de varios. Depende de la literatura a la que acudamos, algunos aplican el uso de MFA a sistemas donde solo satisfacemos las tres premisas del: Algo que somos, Algo que tenemos y Algo que sabemos. Esto no es correcto, lo acertado es decir que MFA es aplicable cuando un sistema requiere 2 o más sistemas de autentificación que satisfacen una, dos o tres de las premisas dadas . 2FA es exactamente lo mismo, pero cuando se requieren sólo 2 sistemas de autentificación. 2FA por tanto es un sistema MFA.

Hoy tenemos que darle las gracias al señor Don Google de todos estos artículos. Ha sido y es una de las piedras más fuertes que ha apostado por los sistemas modernos de autentificación, incluso algunos de ellos convertidos hoy en estándares han nacido en su seno. Con 2FA sucede lo mismo, fueron los pioneros en implementarlo a nivel doméstico y de forma masiva en las cuentas de sus usuarios.


Necesidad de sistemas MFA

Siempre que aparece una tecnología nueva, o empezamos a usarla, hay que preguntarse cual es su razón de ser. No soy una oveja que hace o dice lo que le mandan, me gusta sacar mis propias conclusiones, y más importante, saber el por qué de las cosas. Así que de nuevo me pregunto… ¿Es necesario usar un MFA?

Bien, el concepto no es nuevo, sencillamente es aplicar el simple: Si uno es bueno, dos es mejor. Eso es cierto, pero no siempre quiere decir que sea necesario, útil o que incluso sea una desventaja. No es la primera vez que escucho decir que el software X para cifrado de datos es el mejor y más seguro del mundo porque cifra hasta 3 veces (una encima de la otra) el contenido… no discuto que sea más seguro, discuto el echo de que no es necesario, si el cifrado primero es seguro, el resto no son necesarios y añaden complejidad.

Entonces.. ¿Necesitamos sistemas MFA o no? Desde mi punto de vista, a día de hoy, mientras sigamos dependiendo de sistemas tradicionales comprendidos de Usuario/Contraseña, un sí rotundo. ¿Añaden complejidad y entorpecimiento al usuario? Sí. ¿Requiere normalmente molestarnos? Sí. Pero ganamos mucho, enormemente.

El problema viene de lejos. El modo tradicional de autentificación ha sido (y será aun por muchos años) el clásico Usuario/Contraseña. Pero dicho método ha demostrado durante años que es totalmente ineficaz para proteger de un modo más o menos fiable nuestras credenciales. Demasiados problemas: Necesidad de memorizar cadenas imposibles para considerar la contraseña “segura”, impotencia y desconocimiento de los canales de transmisión de la contraseña, robo de nuestras contraseñas en los sistemas de tercero, robo de nuestra contraseña en nuestros propios equipos, robo de nuestra contraseña en equipos de terceros donde la introducimos…

Google entendió esto hace muchos años. Hace más de 9 años que lanzó la aplicación Google Authenticator, y ya habían pasado incluso algunos años más desde que lanzase la posibilidad de habilitar 2FA a través de códigos OTP (los veremos más tarde) vía SMS/llamadas/impresión. El resultado fue inmediato, y el % de accesos no autorizados a cuentas de Google cayó de forma significativa para aquellos que los usaban. Por desgracia el % de usuarios que a día de hoy usan sistemas MFA en sus servicios es pequeño, por desgracia, no creo que llegue al 10%.

¿Son realmente seguros estos sistemas? No hay nada que sea inviolable, y existen técnicas de engaño y/o robo de datos que puedan hacer saltar una cuenta de todos modos, pero lo cierto es que un sistema 2FA bien establecido y con un usuario que no sea descuidado, es casi impenetrable. Una autentificación sencilla por usuario/contraseña es extremadamente sencilla saltarla, raro es el día que no se filtran por canales extraoficiales cientos, miles o millones de credenciales.

Es por ello que se intenta llegar a un compromiso entre usabilidad y seguridad. Sería muy seguro aplicar 10 sistemas uno encima del otro, pero eso sería extremadamente molesto y consumiría mucho tiempo. En cambio, tal vez, introducir un código secundario si hay sospecha, no es una molestia demasiado grande después de todo.


MFA de forma condicional

Aunque es extremadamente recomendable a día de hoy usar sistemas MFA, no significa que estos sean realmente necesarios 24 horas al día los 7 días de la semana. Los sistemas de autentificación tradicionales tienen sus ventajas, son rápidos, solo requerimos nuestra memoria, podemos compartir una cuenta si así lo quisiésemos de forma simple… eso no significa que sean seguros, pero son cómodos, y muchas veces suficientes.

Los MFA no sustituyen los sistemas de autentificación vistos, los complementan. Cuando la seguridad tiene que ser máxima, el uso de MFA debería de ser obligado, por ejemplo una compra con tarjeta de crédito debería de requerirnos siempre una confirmación adicional como un SMS. En cambio, para la mayoría de los servicios que usamos lo ideal es poder usarlos de forma condicional, no siempre, sólo cuando pueda existir duda razonable.

Esto por desgracia no depende de nosotros, son los servicios/software que usamos los que deben de permitirnos no solo usar sistemas MFA, sino cuando solicitarlos, si el 100% de las veces o sólo cuando el sistema/software estipule que es necesario. Aquí cada desarrollador establece el umbral que estime.

Por ejemplo, la mayoría de servicios que permiten el uso de MFA detectan la huella del navegador web usado para acceder a su servicio (ya sea por user-agent, por un ID único que calcule, por una cookie…), y si el acceso se está realizando desde un “navegador” que no ha sido previamente “autorizado”, obligarán la verificación por MFA. Esto es lógico, habitualmente usamos los mismos equipos/navegadores/aplicaciones para acceder a nuestros servicios, con lo que el sistema detecta si usamos otro dispositivo/software/aplicación, por si alguien estuviese intentando acceder de forma ilegítima.

Otra forma de detectar de forma habitual estos accesos es por medio de localizaciones basadas por IP, aunque ya de por sí la geolocalización IP es cuanto menos discutible. Pero el sistema podría por ejemplo obligar a autentificarse por MFA si el acceso se realizase desde una IP proveniente de otro país,

La idea siempre sería la misma, intentar usar sólo sistemas MFA cuando se pudiese sospechas que es otro el que accede. Google ya usa IA para determinar estos comportamientos. Cuanto menos tengamos que usar MFA, menos molestia, y la seguridad se mantendrá siempre y cuando el sistema “detecte” bien los accesos no autorizados.

Por supuesto, repito, si la seguridad es primordial, sencillamente se forzaría SIEMPRE un sistema MFA


Sistemas MFA

En teoría podríamos usar cualquier sistema de autentificación aplicado de forma descendente, y ya tendríamos un sistema MFA, y ya hemos hablado de varios de ellos. No obstante, hay algunos sistemas de autentificación que a día de hoy se usan casi exclusivamente para sistemas 2FA/MFA.

Aquí vamos a ver los dos sistemas más ampliamente extendidos. Repito, no son los únicos, sólo los más habituales.

El primero del que vamos ha hablar es con seguridad el más conocido por todos, me extrañaría que alguno no lo hubiese usado alguna vez para algún servicio, empezando por la mayoría de las compras. Hablamos de los códigos OTP, o códigos de un sólo uso (One Time Password).

El segundo es menos conocido, aunque su importancia es indiscutible, y muy posiblemente capital, en el presente, y de seguro en un futuro muy cercano. Hablamos de U2F, de la mano de la FIDO.


Códigos OTP (HOTP y TOTP)

Un código OTP (One Time Password) no es más que una cadena alfanumérica (generalmente 6 números) que es usada a modo de contraseña generalmente como sistema MFA, con la particularidad que es de un solo uso, no nos servirá para una futura identificación MFA. Esto es bastante ingenioso, si solo puede usarse una vez, podemos “generarlas” en el momento de necesitarlas y no tener ningún tipo de miedo o reparo de que un tercero pueda apropiarse de ella, puesto que, repito, es d un solo uso.

El ejemplo más simple de esto es los SMS de confirmación que nos envía el banco cuando hacemos una compra con un código numérico. Ese código por lo general es basado en tiempo, y si no lo usamos en unos segundos (en todo caso un par de minutos), deja de tener validez. Los bancos no son los únicos que usan estos códigos, los ejemplos los encontramos en todos lados: El código CLAVE que se solicita al gobierno para trámites online sin certificado, los sistemas de recuperación de contraseña que usan la mayoría de los servicios online (ya sea por SMS o Mail)…

Existe una enorme variedad de algitmos/sistemas OTP, muchos de ellos privados. Aquí vamos a ver dos de ellos, estandarizados, y de nuevo los más ampliamente usados. La gran ventaja que tienen es que al estar estandarizados (y de código abierto), es que además de seguro, disponemos de todo el software que deseemos ya creado y bien documentado, software implementado en autentificadores que nos sirven para la inmensa mayoría de servicios (como Google Authenticator), como librerías usadas para tokens de seguridad, o incluso el software necesario para implementarlo en un servicio/aplicación que queramos crear. Es decir… que mientras los desarrolladores/proveedores quieran usarlos, no tendremos que depender de mas software o dispositivos externos, todo es más compatible, más simple.

Tanto HOTP como TOTP están basados en HMAC (HMAC-SHA1 para ser más exactos). Ambos son muy similares, la diferencia en ellos radica el factor que podemos denominar unicidad, es decir, el factor que hace que el código OTP que generan sean únicos. Quitando eso, tanto el cálculo del valor OTP, el algoritmo usado, el hash… todo es igual. Eso no significa que esa diferencia no sea importante, de echo esa diferencia tiene infinidad de implicaciones técnicas.

-HMAC:

Un Hash, como he explicado aquí muchas veces, no es más que una función matemática que es capaz de convertir unos datos de entrada de tamaño arbitrario, a una cadena de salida con una longitud determinada, de modo que siempre que la entrada tenga exactamente el mismo contenido bit a bit, la salida será igualmente la misma.

Un HMAC es básicamente lo mismo que un Hash, pero la salida es dependiente también de una clave que formará parte (de una forma concreta) de los datos de entrada. En esencia, nos permite generar un Hash también, pero a diferencia de un Hash normal que solo requiere de los datos de entrada para verificarse/recalcularse, el resultado de un HMAC solo podrá verificarse/recalcularse si se posee la clave usada, de lo contrario el resultado sería diferente.

Matemáticamente, y simplificando, un HMAC usando un Hash cualquiera H, una Clave C y unos datos de entrada E, se calcularía así:

HMAC = H ((C XOR 0x5c5c5c…) || H (C XOR 0x363636…) || E )

Es decir, que el HMAC será el resultado de realizar el Hash H a la concatenación || de 3 bloques:
1º, la operación XOR de la clave con Bytes 0x5C.
2º, el Hash H resultante de la operación XOR de la clave con el Byte 0x36
3º, los datos de entrada

Si se comprende en esencia como se calcula y que es un HMAC, es bastante sencillo comprender los códigos HOTP/TOTP, puesto que básicamente son HMAC calculados. Así que aquí el truco radica básicamente en como hacer que sean siempre “únicos”, y como hacer para que el resultado sea una secuencia sencilla, en el caso de códigos HOTP/TOTP, una secuencia numérica de al menos 6 cifras (pueden usarse 7 y 8 también)

El estándar HOTP/TOTP establece además que el Hash usado para HMAC debería de ser SHA-1 (20 Bytes), aunque existen implementaciones que permiten usar otros Hash alternativos, como SHA-256. Por estandarización, vamos a usar siempre SHA-1.

-Clave Secreta

A diferencia de un Hash, un HMAC requiere de una clave también como como dato de entrada, además de los propios datos que se quieren pasar por el HMAC. Para los códigos HOTP/TOTP esta clave sería la que nos va a permitir poder generar dichos códigos en cualquier software/hardware, es lo que va a hacer que nuestro generador sea seguro. Si dicha clave fuese puesta a disposición de terceros, podrían generar códigos HOTP/TOTP válidos para suplantarnos.

Cuando configuramos cualquier servicio para usar HOTP/TOTP, lo único que se genera es por tanto la clave secreta que va a usarse para la autentificación. Dado que tenemos que ser capaces de autentificarnos frente al proveedor que sea, dado que básicamente usamos HMAC para la autentificación, tanto el cliente que se autentifica como el servicio que lo requiere, deben de usar la misma clave secreta. Por regla general esta clave no necesitamos memorizarla, por lo general es introducida en nuestro autentificador manualmente o por un código QR, y una vez realizado, no la necesitaremos más, el autentificador se encargará de generar los códigos de forma automática.

En algunas ocasiones puede ser deseable conocer dicha clave secreta. Por ejemplo si deseamos usar otro autentificador, o a modo de backup.

Como nota importante, citar que dado que la clave maestra va a residir de un modo u otro en ambas partes, en el lado del usuario y en el lado del servicio que sea, siempre va a ser susceptible a ser “robada” o accedida con malas artes. Dicho de otro modo, si una base de datos del servicio que fuese, con usuarios/contraseñas, fuese filtrada, y en la misma base de datos se reflejase la clave maestra de los códigos OTP de aquellos usuarios que tuviesen habilitada la MFA, nuestra seguridad estaría igualmente comprometida.

-Mensaje a calcular el Hash

Esto lo veremos más adelante, porque aquí es donde radica las diferencias entre TOTP y HOTP, en cual es el mensaje o los datos de entradas que se va a usar como entrada del Hash.

-Truncado y Conversión de HMAC a Decimal

HOTP/TOTP no es sólo que esté basado en HMAC, es que el código que vamos a usar es realmente un resultado HMAC que se va a truncar primero (para limitar su longitud) y convertir después a decimal para que el usuario lo tenga sencillo a la hora de introducirlo.

En principio se podría usar directamente el resultado HMAC claculado. Pero este tendría dos problemas:

-Un Hash SHA-1 tiene una longitud de 20Bytes, eso implicaría tener que introducir un valor de este tipo: 0x000102030405060708090a0b0c0d0e0f10111213

-La salida de un Hash generalmente es hexadecimal, incómodo para el usuario. Recordemos que estamos usando estos códigos como MFA, aun cuando fuese una cadena mucho más corta, es lento.

Estos dos problemas se solucionan de un modo sencillo: Truncamiento a 4Bytes y conversión. Es decir, el Hash SHA-1 se trunca a un valor mucho más modesto de 4Byte, y posteriormente se convierte a decimal con el número de cifras deseadas, generalmente 6.

El truncado no es tan directo como podría pensarse. Se podría directamente tomar los 4 primeros Bytes o los 4 últimos… pero se prefirió que el truncado fuese dinámico por mayor seguridad. Lo que se realiza es usar un offset concreto que nos va a determinar donde empiezan los 4 Bytes que vamos a tomar, y ese offset viene determinado por los últimos 4bits del Hash. 4 Bits codifican 16 valores, con lo que el offset máximo sería el 0xf, dado que el Hash SHA-1 son 20Bytes, en ese caso escogeríamos los últimos 4 Bytes.

La conversión es mucho más simple, se trata de tomar dicho valor como decimal y obteniendo sólo las cifras que nos interese. Como se va a operar, y dado que un número de 32bits (4Bytes) puede ser interpretado con signo o sin signo, para evitar problemas con las implementaciones, se suprime directamente el bit de mayor peso, con lo que nos quedamos a efectos prácticos con un número entero positivo de 31bits. Y una vez que tenemos dicho número, simplemente calculamos el resto de dicho número dividido por el número de cifras que queremos obtener. Es decir, que si queremos obtener 6 cifras, lo dividimos entre un millón, el resto por tanto será obligatoriamente un número entre 0 y 999999

Ejemplo simple:

-HMAC Resultante (20 Bytes):
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13

-Offset: 0x3 (Último Byte -> 0x13 últimos 4Bits 0x3)
-4 Bytes dinámicos truncados: 03 04 05 06
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13
-El número es ya menor o igual de 31 bits, el bit 32 es ya cero
-Número Decimal: 0x03040506 = 50595078
-Resto para 6 cifras: 50595078 mod 10^6 = 595078

Código OTP: 595078

-Códigos HOTP

A pesar que son el alma mater, su uso es marginal en comparación con los códigos TOTP.

Como se dijo anteriormente, lo que diferencia un código HOTP con un código TOTP es lo que se usa como “mensaje” de entrada al Hash, que así mismo le dan la propiedad a los códigos OTP a que sean de un sólo uso.

En los códigos HOTP, este mensaje es un contador, un número de 8Bytes. Cuando se configura por primera vez el autentificador para generar códigos HOTP, las dos partes deben de sincronizar/preestablecer el valor inicial de este contador, al margen de generar una clave maestra. Este contador por lo general se establece a cero, pero puede fijarse cualquier valor inicial si así se prefiriese, la cuestión es que ambas partes tienen que conocer este valor

Una vez sabido, el resto es trivial… ¿el truco? Cada vez que el autentificador genera un HOTP nuevo, el contador se incrementa en 1, y cada vez que el servicio al que se accede nos autentifica, aumenta también su contador en 1. Así pues cada código generado es único, puesto que el siguiente tendrá el contador aumentado, y por ende el HMAC resultante será diferente.

En este esquema es imperativo que ambas partes lleven el mismo contador. Podrían suceder dos eventos no deseados: El primero, que nos autentificásemos desde otro dispositivo, con lo que el servidor habría aumentado el contador, y no así nuestro autentificador. En este caso se podría resincronizar el contador de nuestro autentificador sencillamente generando X OTP nuevos. El segundo caso es más dañino, y se daría si el contador de nuestro autentificador va por delante, en ese escenario sería necesario un sistema para resincronizar el contador del servidor, lo cual no es trivial… por ejemplo si generasemos un HOTP cuando no debiésemos.

La gran ventaja de los códigos HOTP es que no requieren nada, incluso los token de seguridad que existen son sencillos. El inconveniente es depender de dicho contador y de los problemas que podrían ocasionar si se desincronizasen. Esto ha provocado que a día de hoy sean infinitamente más habituales los TOTP,

Existe otra peculiaridad de los códigos HOTP que puede ser buena o mala, según se mire. Los códigos HOTP son de un solo uso, pero mientras que el contador no se incremente, dicho código no tiene fecha de caducidad. Es decir… conociendo el contador y la clave secreta puedo generar potencialmente el código HOTP que quiera. Imaginemos que genero los códigos para el contador C=0 hasta C=10. Esos diez códigos OTP tendrán vigencia mientras que el contador del servicio que sea no vaya sobrepasando el contador con el que se generó. Esto podría permitirnos crear de antemano los HOTP que quisiésemos, pero en contra, es inseguro que tengan una validez indefinida, válido mientras que el contador del sistema aun coincida.

-Códigos TOTP

Los códigos TOTP son los más usados en la actualidad. Son una derivación directa de los códigos HOTP, un hermano muy cercano a ellos. Mientras que los HOTP basan su unicidad en un contador incremental concreto que hace las funciones de mensaje a pasar por HMAC, en los códigos TOTP se usará como contador la diferencia de tiempo entre la hora actual T y una hora inicial T0 (ambos en segundos), dividido por el intervalo de segundos que queremos que el código sea válido,

Como vemos, toda la formulación sería exactamente igual, con la salvedad que el “contador” a usar en esta ocasión (el mensaje que se va a pasar a HMAC) es dependiente de la hora actual. Para ello se usa notación epoch del tiempo, un numero decimal.

El tiempo Epoch es el sistema de conteo de tiempo más usado en la actualizada en el mundo de la tecnología. No es otra cosa que el número de segundos que han transcurrido desde “el instante cero”, que fue establecido en el 1 de Enero de 1970, a las 00.00 en horario UTC, hasta el tiempo actual, o hasta el tiempo que se quiera calcular. Eso quiere decir, que en este preciso instante el tiempo epoch es de 1562558718, que corresponde al 8 de Julio de 2019 a las 4.05 y 18 segundos (UTC).

Como hemos dicho, definimos el contador C como:

C= (T – T0) / Intervalo

Siendo Intervalo el número en segundos que queremos darle validez (por defecto 30s), T0 un tiempo inicial si se quiere (cero por defecto) y T la hora actual. La división se realiza con suelo, es decir… si la división no alcanza el entero, se redondea siempre con el valor menor. Esto permite precisamente que el código TOTP permanezca siendo el mismo durante ese intervalo de tiempo.

Este sistema permite por tanto crear códigos OTP no sólo únicos en función del tiempo actual, sino también que los códigos TOTP sean sólo válidos por una pequeña ventana de tiempo, pasada la cual, el contador C habrá cambiado debido al incremento del tiempo. Dado que el tiempo es necesario en el mismo momento de solicitar el código TOTP, no serviría de nada algún intento de apoderarse de unos cuantos, como sucedía con HOTP. Sí, podríamos generar los códigos que quisiésemos, pero esos códigos solo serían válidos en un momento concreto en el tiempo.

No es oro todo lo que reluce, y los códigos TOTP tienen una desventaja clara con los códigos HOTP. Los códigos TOTP necesitan conocer conocer la hora actual, por lo que requieren de un reloj externo o interno, sincronizado correctamente, de modo que el reloj usado por el cliente tenga un desfase mínimo con el del servidor. Es posible que un par de segundos de desfase podría no afectar al código TOTP, pero un minuto sería totalmente inaceptable.

Estamos de acuerdo que estamos rodeados de dispositivos con relojes internos/externos. Pero muchos dispositivos de seguridad y en muchos entornos vamos a ver que esto es un problema. Para empezar, si un dispositivo tiene un reloj interno del tipo que sea, requerirá de una fuente de alimentación para mantenerlo corriendo, y algún modo igualmente de sincronizar su reloj.


FIDO U2F

Hace algo más de 5 años que oí por primera vez sobre la FIDO (Fast IDentity Online) Alliance. Por entonces no me parecía mucho más que una interesante iniciativa nacida del seno de Paypal, Lenovo y Tok Tok Lab, para crear/trabajar en estándares para la identificación online. Entonces me parecía algo un tanto rompedor e incluso atrevido, sin micho camino, a fin de cuenta como iba a ser posible cambiar algo tan universalmente aceptado sistema de identificación de usuarios/contraseñas.

En solo unos meses la FIDO había pasado de 3 fundadores a un gran elenco de miembros, ya no solo demasiados para ser enumerados, sino que además entre ellos la mayoría de los pesos pesados de Silicon Valley. Por nombrar algunos que creo que a nadie les resultarán desconocidos tenemos a Amazon, Facebook, Google, Intel, Microsoft, Qualcomm, Samsung… y algunos miembros quizás de segunda línea pero igualmente emblemáticos como RSA, VISA, MasterCard, Yubico, varios Bancos… en realidad hay muy pocas compañías de gran peso que no pertenezcan a la FIDO, quizás la más destacada ausente Apple, pero nada que nos sorprenda demasiado.

Particularmente, Google y Yubico fueron desde un principio los más implicados, y muy posiblemente a día de hoy tengamos que agradecerles el trabajo que han realizado, no solo contribuyendo directamente a la FIDO, sino publicitando e implementando la tecnología. Así, Google y Yubico dieron a luz U2F, “Universal 2nd Factor”. Querían crear una solución realmente segura para sistemas MFA que fuese lo más sencilla posible para el usuario.

FIDO U2F se integra por lo general como un dispositivo USB (existiendo igualmente dispositivos NFC/Bluetooth e incluso por software), pero para facilitar aun más su uso estos se identifican al sistema como dispositivos HID, lo que en la práctica se traduce con que no sea necesario ningún tipo de Driver o software adicional para ser usados.

Los códigos OTP pueden tener sus vulnerabilidades, U2F es prácticamente imposible de burlar, y así lo demuestran por cierto los últimos datos de Google, que pondremos más tarde. El funcionamiento de U2F se fundamenta en un sistema de Desafío-Respuesta (Challenge-Response) basado en criptografía simétrica. Esto va a permitir que cada dispositivo U2F vaya a tener una clave privada única, generada en tiempo de fabricación, y que jamás abandonará el propio dispositivo.

-Elemento Hardware

Con los códigos OTP necesitamos un autentificador, con U2F también, pero en este caso suele ser un elemento hardware. Se han creado multitud de formatos de ellos. Estos fueron mis 2 primeros dispositivos U2F, con algo menos de 5 años, aun en uso:

La idea con la que U2F se creó es que fuese lo más sencillo posible para el usuario como hemos dicho. Sin Drivers, sin software, solo un puerto USB donde insertar. A día de hoy tenemos dispositivos U2F que funcionan por NFC o Bluetooth, sin que sea necesario siquiera un puerto o un contacto físico.

Por lo general, las llaves U2F funcionan de un modo directo y rápido, casi sin interacción por parte del usuario (a veces sin ella). Sí, tiene un inconveniente, y es que para poder usar U2F requerimos por ende un dispositivo (llave) U2F. Por cierto, la mayoría se fabrican resistentes a todo tipo de inclemencias, y generalmente perforadas para transportarse en llaveros.

-Funcionamiento Básico

Al igual que un sistema basado en OTP, antes de comenzar a usar una llave U2F, se requiere un proceso de “registro”, en el cual, el sistema compatible con U2F va a registrar nuestra llave U2F, va a asociarla a nuestra cuenta, para que a partir de dicho momento pueda ser usada como sistema MFA.

Las llaves U2F se registran al servicio que queramos, pero no están atadas a ellos. Es decir, que la misma llave U2F debería de poder ser usada en cualquier servicio que quisiésemos, incluso en diferentes cuentas de los mismos servicios, sin que esto sea un perjuicio a la seguridad. Esto se verá en el siguiente apartado.

Por seguridad, dado que es un dispositivo que por lo general conectamos físicamente o dejamos sobre un lector NFC, se requiere siempre algún tipo de interacción con ella para permitir su uso. Esto tiene sentido, si la llave U2F pudiese ser usada sin interacción alguna, simplemente estando conectada al equipo en cuestión, sería vulnerable a malware en el equipo, de modo que un atacante externo podría hacer uso de él. Este tipo de medidas de seguridad las encontramos en muchos entornos/dispositivos seguros, normalmente denominadas protecciones de presencia física, los módulos TPM por ejemplo las implementan también.

Esta interacción por parte del usuario suele ser algo tan sencillo como presionar un pequeño botón o zona de la llave U2F. En mi vieja llave U2F este sistema de detección de presencia era aun más rudimentario, no existe botón, su uso está condicionado a que sea directamente insertada. Es decir, que si no se inserta en el momento que se va a usar, no funciona, pasados unos segundos de ser conectada, si se requiere su uso de nuevo sería necesario sacarla y volverla a meter.

Una vez registrada nuestra llave U2F en el sistema, su uso es más simple y fácil que los códigos OTP, no tendremos que teclear nada, simplemente interaccionar con nuestra llave U2F (si está ya conectada) o conectarla e interaccionar con ella si no lo estaba, todo sucede en cuestión 1-2 segundos. Por supuesto, siempre y cuando el servicio que sea ponga en marcha la necesidad de usar MFA, se aplican los mismos principios que los códigos OTP, lo ideal es que solo se requiera en determinados momentos, o siempre si la seguridad es totalmente necesaria.

Esto es vital. Recordemos una vez más que U2F es un sistema para ser usado en entornos MFA/2FA. Seguro que más de uno estará pensado que este tipo de dispositivos son estúpidos, que cualquiera podría robárnoslo o cogerlo prestado, y podrían hacer uso de ellos. Sí, es cierto, pero lo mismo si nos roban nuestro autentificador OTP. La cuestión es que estamos repito ante un sistema para ser usado en entornos MFA/2FA, por sí misma la llave U2F no permite el acceso a nada, el acceso principal se realiza por lo general por sistemas tradicionales de usuario/contraseña, sólo cuando la primera autentificación se ha realizado con éxito sería necesario usar U2F.

En otro capítulo veremos este matiz tan grande, y es la principal diferencia con FIDO2. Si un usuario malintencionado quisiese acceder a una cuenta nuestra protegida con U2F, necesitaría en primer lugar las credenciales tradicionales, pero estas no le valdrían de nada sin la llave U2F. Del mismo modo si tuviese la llave U2F pero no usuario/contraseña (por poner un ejemplo), estaría igualmente con las manos atadas. Así que en esencia la seguridad suele estar garantizada, las llave U2F forman parte de “Algo que tenemos”, mientras que usuario/contraseña formarían parte de “Algo que sabemos”.

-Funcionamiento Interno

Bueno, la parte sencilla acabaría ahí, para el usuario que sólo quiere proteger sus cuentas, ya sabe como hacerlo, es rápido y sencillo, y tenemos llaves U2F casi regaladas (4€ hace 5 años por las dos que habéis visto en la foto). Pero esto no sería un artículo mío si dejásemos las cosas ahí, cuando lo realmente interesante y maravilloso de U2F viene ahora… ¿Como funciona? ¿Es realmente seguro? ¿Que futuro tiene?

De nuevo estamos ante la maravilla de la criptografía pública. No nos equivoquemos, sistemas seguros hay desde hace muchos muchos años (al menos hasta la fecha), el problema es que estén bien diseñados y que quieran usarse. Hay que decir que Google y Yubico hicieron muy bien sus deberes y crearon un sistema extremadamente ingenioso, sencillo y seguro… hasta el punto que FIDO2 es ya una realidad, y lo veremos en otra entrega.

El sistema de funcionamiento de FIDO U2F está basado en un sistema de Desafío-Respuesta con criptografía de clave pública. Esto significa que el destinatario X enviará lo que llamamos un “desafío” al usuario para que su llave U2F lo “resuelva”, enviando su respuesta de nuevo al destinatario. El destinatario verificará la respuesta, si es correcta autorizará el acceso. Con los códigos OTP el sistema era totalmente diferente, recordemos que con OTP ambas partes poseían la misma clave secreta, y por ende podían generar en el momento que fuese el mismo código OTP, dando acceso si este coincidía. Aquí se abandona ese esquema.

Teniendo en cuenta este sencillo esquema, la seguridad va a venir dada por que tipo de desafío se va a realizar, si podemos asegurar que la respuesta sea inequívoca y como puede el servidor verificarlo.

El desafío en este caso son Hash SHA-256 calculados a ciertos datos de entrada llamados “Datos de Cliente”, entre los que se encuentra el origen, el desafío enviado por el servidor, el tipo de petición o el ID del canal TLS usado.

Todos los dispositivos U2F tienen internamente grabada una clave privada que es única para cada dispositivo. Los fabricantes firman documentos en los que se asegura que dicha clave privada se genera en tiempo de fabricación dentro del propio dispositivo, sin que sea posible extraerla/conocerla de ningún medio, ni siquiera los propios fabricantes. Obviamente este es un punto crítico, dado que la seguridad de U2F se basa generalmente en dicha clave, puesto que la mayoría de dispositivos usan esa clave privada para posteriormente generar el resto.

De forma genérica, el funcionamiento de U2F consisten en que cada vez que nuestra llave U2F se registra en un servicio nuevo (o en otra cuenta del mismo servicio), esta va a generar un par de claves criptográficas únicas, la parte pública será guardada en el servidor remoto, es la parte conocida, mientras que la parte privada y secreta quedará sellada en el propio dispositivo U2F.

Registro

El registro comienza enviado el servidor una salva de datos al dispositivo del usuario. Entre esos datos, como mínimo se incluye el ID de la aplicación (servicio, la URL del servicio). Todo ello es recogido por el dispositivo del usuario (generalmente el navegador Web), y compone el mensaje que enviará a la lleve U2F. A todo ello, como veremos con FIDO2, se añadirían datos de atestación, tipo de algoritmo a usar y otros datos.

Ejemplo de Registro sencillo, mensaje enviado por el servidor y respuesta de la llave U2F:

{
"version":"U2F_V2",
"appId":"https://blog.theliel.es",
"challenge":"GmEuTgUdFfd3dk_I5g58y-e4qV9Hg0c6SFgJSuCXWOM"
}

La llave U2F procesará la información que ha recibido, y generará un par de claves (privada/pública). La parte privada la “almacenará” conjuntamente con un handle, un identificador de la clave para poder “buscarla” luego cuando se requiera. La parte pública se devolverá al servidor en cuestión, junto con la atestación en caso de que fuese necesaria, y otros datos relativos a la propia llave U2F.

KeyHandle: ...Gez0V8kKPNbNX_CtSSYA
publicKey: ...ai0mOfugNd9QpPnFTzeil8s
Certificate: ...fEN6VNRqYsi-bu-2lbirFEFg

La atestación no es obligatoria. La atestación es el procedimiento por el cual una entidad externa, en este caso el servidor donde hacemos el registro, puede verificar la llave U2F que estamos usando. Para ello la Llave U2F firmará un desafío enviado por el servidor con otra clave privada especial que pueden tener (no es obligada) las llaves U2F, que es la clave/certificado de atestación. Si hay atestación, la llave U2F enviará al servidor no solo el desafío firmado criptográficamente, sino también su certificado público. De este modo el servidor podrá verificar la firma con el certificado de atestación que ha sido entregado, y paralelamente realizar las comprobaciones que el servidor estime sobre dicho certificado de atestado.

¿Para qué se puede usar esto? Para obligar el uso de determinadas llaves U2F, como vimos también en los módulos TPM. Imaginar que el servidor solo quiere permitir llaves U2F de Google. Para ello solo tendría que tener en el servidor almacenado como confiable el certificado público Raiz de Google que emite los certificados de atestado de las llaves de Google. Así, cuando una llave respondiese un desafío para atestado, podría comprobar si el certificado público que les ha enviado la llave efectivamente verifican la firma del desafío, y si la verificación es correcta, solo les quedaría comprobar ahora la firma del certificado público de atestado entregado por la llave. Si la validan, pueden tener la seguridad que la llave usada es sí o también una llave de Google, sin que sea posible de ningún modo emularla o suplantarla.

Autentificación

Cuando se requiere la autentificación el proceso no es complicado. El servidor envía un desafío al cliente, que posteriormente enviará a la llave U2F. Dicho mensaje incluirá también el handle que le envió la llave en el registro, para que la llave pueda encontrar la clave privada correspondiente, la URL (siempre importante) y por supuesto el desafío.

{
"version":"U2F_V2",
"appId":"https://blog.theliel.es",
"keyHandle":...Gez0V8kKPNbNX_CtSSYA,
"challenge":"ILS-SS4kSL7M4upLYWiFmkR3K4jP9oS-ngYB4SzERuQ"
}

Dicho mensaje es enviado al final a la llave U2F. A través del handle la llave U2F debería de ser capaz de acceder a la clave privada que ha generado previamente para dicho servicio, y que está asociada a dicho handle, y con esa clave privada firmar el desafío interpuesto por el servidor. La llave U2F envía de vuelta otro mensaje con datos relativos a la propia llave, el tipo de firma que se ha realizado… y obviamente la firma del desafío.

El servidor, solo tiene que verificar la firma de la llave U2F con la clave pública que tiene almacenada en la cuenta del usuario. Si la firma es correcta, puede estar 100% seguro que la llave U2F empleada en el registro es la misma que se está usando para autentificarse, y conceder acceso.

-Almacenamiento de Credenciales

Una sola llave U2F debería de ser capaz de ser usable en un número arbitrario de servicios, pudiendo usar la misma llave en diferentes cuentas para un mismo servicio y/o diferentes servicios.

Pero hemos dicho que por cada registro, la llave U2F debería de ser capaz de generar un par de claves diferentes. Si fuese así… ¿como podría una llave U2F almacenar tal cantidad de datos de un modo seguro? Por supuesto, en una memoria de unos cuantos MB sería suficiente para almacenar cientos de ellas, pero estos son dispositivos de seguridad que impiden el acceso/extracción externo, esto sería muy caro, y las llaves U2F serían más grandes.

Otra opción sería poder almacenar un número muy limitado de servicios, tras los cuales tener algún modo de “reseteo”, para poder usarse en otros servicios a expensas de borrar los anteriores. Esto tampoco es práctico.

Otra opción que se llegó a usar en alguna llave U2F de cuestionable procedencia y seguridad, radicaba en usar siempre en todos los servicios el mismo par de claves, con lo que la clave pública era siempre la mismo. Eran usables, pero si se hubiese comprometido la clave, todos los servicios quedarían igualmente expuestos.

A día de hoy, la mayoría de llaves U2F usan sólo una clave privada que podemos llamar “maestra”, como hemos explicado anteriormente, y esta clave secreta será usada para generar a su vez y al vuelo las claves privadas/públicas que sean necesarias, sin almacenarlas, no será necesario porque cuando se requieren, son generadas exactamente las mismas claves para el servicio concreto. Es solo cuestión de ingenio, es interesante.

Veamos por ejemplo la solución que aplica Yubico con sus llaves de seguridad.

Cuando un servicio solicita un registro de una llave U2F, envía al navegador el ID de la aplicación (la URL) y otros datos, como ya hemos comentado. Lo que Yubico hace aquí es concatenar ese ID con un nonce (una cadena generada aleatoriamente en ese momento), y usando la clave secreta (única para cada llave) aplica a esos datos un HMAC-SHA256. El resultado, es usado como clave privada del servicio en cuestión, y paralelamente se le calcula la clave pública. Llegados a este punto ya tendríamos la generación de la clave privada/pública, pero hace falta algo más.

Una vez que se obtiene la clave privada del servicio, se vuelve a concatenar el ID de la aplicación con, esta vez, la clave privada recién calculada, y se vuelve a proceder a realizar un HMAC-SHA256 con la clave secreta. El resultado obtenido será concatenado con el nonce que se usó a la hora de generar la primera vez la clave privada, y dicha concatenación formará el KeyHandle.

La respuesta por tanto de la llave U2F será el KeyHandle (el resultado del segundo HMAC-SHA256) concatenado con el nonce) y la clave pública.

¿Como se realiza la autentificación? Fácil. El servidor enviaría al navegador (y este a la llave) el KeyHandle, la URL (ID de la aplicación) y el desafío a firmar. La llave hemos dicho que no tiene almacenado nada, pero no le hace falta. El KeyHandle que el servidor le envía lo separa, y con ello obtiene el nonce que se usó cuando se generó, y con el ID de la app y en nonce solo tiene que aplicar de nuevo HMAC-SHA256 con su clave secreta para obtener la clave privada asociada (si los datos de entrada son iguales y la clave aplicada también, el resultado es el mismo). Con la clave privada obtenida firmaría el desafío, y lo devolvería al Servidor. El servidor podría verificar la firma, y por ende conceder acceso.

Gracias a este esquema es posible usar la llave en cuantos registros se quiera, no hace falta resetear, no hay nada que resetear, la llave aunque puede estar usándose en cientos de servicios, realmente no almacena ninguna clave, cuando la necesita la genera.

¿Y si quisiésemos usar la misma llave en el mismo servicio pero con otra cuenta? No es ningún problema, en tiempo de registro el nonce generado sería diferente aunque el ID App fuese el mismo. Ello implicaría una clave privada/pública diferente, un KeyHandle diferente…

Existen llaves que simplemente almacenan en una memoria segura (de tamaño limitado) las claves privadas con sus KeyHandles. En esos casos la llave tomaría el KeyHandle y recuperaría la clave privada asociada. El problema de este esquema es que la llave tendría un almacenamiento limitado, lo que implicaría un número limitado de posibles registros antes de tener que resetearla.

imagen de resultados de google sobre seguridad


Conclusiones finales

Lo primero que habría que preguntarse es como de necesario son los sistemas MFA, y si realmente son tan seguros como se dice. A fin de cuenta, sea por códigos OTP o llaves U2F, obviamente se añade una “molestia” adicional al usuario. Si esta pequeña molestia resulta ser una gran medida de seguridad, entonces quizás esté justificado.

Recientemente (Mayo 2019), Google realizó una publicación precisamente hablando de ello. Me he permitido sacar la infografía que puso, con datos bastante esclarecedores sobre todo lo que estamos hablando aquí. Ojo a los datos que vamos a explicar ahora.

La siguiente infografía muestra los diferentes sistemas que posee/usa Google de 2FA, cuando detecta un acceso sospechoso. Los separa entre desafíos basados en dispositivos y basados en cosas que sabemos. Y los divide a su vez en 3 tipos de ataques habituales: Ataques automatizados por Bot, Ataques masivos usando Phising y Ataques dirigidos.

Según estos datos, vemos que los sistemas de “protección” tradicionales consistentes en solicitar información propia como cuentas de correo alternativas, teléfono o incluso ubicación, no demuestran ser muy adecuados. La mayoría muestra una buena defensa contra ataques automatizados (excluyendo el correo electrónico), pero el % de defensa frente a ataques dirigidos o incluso ataques indiscriminados de Phising, es relativo. En el caso, por ejemplo, de usar la ubicación como identificación resulta ser totalmente ineficaz, mientras que el conocimiento del teléfono tampoco aporta mucha seguridad, siendo capaz de proteger solo un 26% y 50% de los casos.

Cuando la seguridad pasa a sistemas más sólidos como códigos OTP (SMS Code), inicio de sesión en dispositivo o seguridad basada en llaves de seguridad (U2F), los datos son rotundos.

Nota: Recordemos que Google usa un sistema “especial” y sencillo de identificación basado en dispositivo, por el cual te envía directamente una notificación a la pantalla de nuestro terminal que podemos aceptar o rechazar en ese momento.

Los 3 sistemas muestran que son capaces de bloquear el 100 de ataques automatizados por bot, y prácticamente también el 100% de los ataques indiscriminados por Phising, exceptuando cuando se usan códigos OTP vía SMS. Esto es explicable debido a que los ataques de Phising han evolucionado notablemente, y los propios Hackers solicitan incluso en los propios formularios engañosos un código OTP. Otros ataques “efectivos” contra los códigos OTP enviados por SMS se basan en solicitar por correo u otro SMS el código recibido con algún engaño. Cuando se usan códigos OTP generados por algún autentificador y no recibidos por SMS, ese 96% llegaría básicamente al 99%.

La principal discrepancia son los ataques dirigidos. Un ataque dirigido no es un ataque fortuito, es un ataque que se realiza contra una persona específica, contra una cuenta concreta que se quiere robar. Estos ataques suelen tener un índice de éxito infinitamente mayor, dado que se emplean técnicas sociales que generalmente están muy muy dirigidas contra dicha persona. Suplantar personas cercanas/familiares, engañar haciéndose pasar por una compañía… cualquier cosa es válida para lograr más información.

En los ataques dirigidos, que son los más complicados de evitar, los códigos OTP por SMS resultaron en que “sólo” lograban frenar 3 de cada 4 ataques, por el motivo que describía anteriormente, es “fácil” engañar a una persona específica para que nos envíe el código OTP del SMS. Me atrevería a decir que este % aumentaría hasta más allá del 90% si se usasen autentificadores OTP propios, sin depender de los SMS.

En lo relativo a la protección notificando en el teléfono, la protección llegaba al 90%, dejando sólo a un 10% expuestos. Esto también es comprensible, es más complicado engañar al usuario que con los SMS, pero podríamos bombardearlo con notificaciones, o enviar un mail/sms preavisándolo que tendría que aceptarlo, o…

Por último, Google no fue capaz de encontrar un solo acceso no autorizado cuando se estaba usando seguridad basada en llave U2F, ni siquiera ataques dirigidos. Es complicado, con las llaves U2F tampoco sirve la ingeniería social, necesitarían nuestra llave física, no hay nada que nos puedan pedir o darles nosotros para que puedan acceder ellos… a menos que sea la propia llave, que obviamente nadie va a regalársela a un desconocido que se encuentre por la calle.

Así que sí, es seguro.

FIDO U2F tiene sus limitaciones pese a todo. A día de hoy, de echo, FIDO U2F podemos decir que ha quedado deprecado, y poco a poco irá siendo reemplazado por FIDO2, del que hablaremos pronto. FIDO2 comparte la inmensa mayoría de la belleza de FIDO U2F, y pude usarse del mismo modo, pero además permitirá mayor comodidad y versatilidad.

Si hace 5 años me hubiesen preguntado si los códigos OTP o las llaves U2F tenían futuro, es posible que hubiese dicho que no. Estos últimos años los sistemas usuario/contraseña se han visto muy dañados con filtraciones constantes, y los códigos OTP están ya a la orden del día. El único inconveniente que tiene U2F por el cual no se ha extendido totalmente, es la necesidad de acarrear con un dispositivo externo, y va a seguir siendo en parte una gran limitación, que por lo general no tienen los sistemas basados en OTP. FIDO2 intenta solucionar esto también, y lo logra en gran medida, pero aun tendrán que pasar posiblemente algunos años para que se asiente.

Sea como sea, los códigos OTP y U2F añaden una mejora enorme en seguridad, no solo ya en el mundo online, todo esto es usable perfectamente en otros entornos, hay multitud de aplicaciones que no trabajan online y que usan tanto OTP como U2F como sistemas de identificación.