paint-brush
Cómo implementar la autenticación de dos factores de Google Authenticator en JavaScriptpor@rajat-sr
31,028 lecturas
31,028 lecturas

Cómo implementar la autenticación de dos factores de Google Authenticator en JavaScript

por Rajat7m2019/10/13
Read on Terminal Reader
Read this story w/o Javascript

Demasiado Largo; Para Leer

Cómo implementar la autenticación de dos factores de Google Authenticator en JavaScript en JavaScript. El tutorial se basa en un proyecto de código abierto llamado Enquirer. Le permite crear mensajes de línea de comandos con estilo que son fáciles de usar y de crear. En este artículo, implementaremos ambos algoritmos, usando NodeJS (JavaScript). Generando un búfer aleatorio de datos usando la biblioteca NodeJS incorporada y luego codificando los datos para codificar los datos. Generar OTP basadas en HMAC también será verificando la OTP, utilizando nuestra implementación de implementación.

Company Mentioned

Mention Thumbnail
featured image - Cómo implementar la autenticación de dos factores de Google Authenticator en JavaScript
Rajat HackerNoon profile picture

Google Authenticator es algo que muchos de nosotros usamos todo el tiempo, pero ¿cuántos de nosotros realmente entendemos cómo funciona bajo el capó?

En este tutorial, desmitificaré la magia detrás de los códigos OTP que caducan de Google Authenticator y le mostraré cómo agregar soporte de Google Authenticator a su aplicación desde cero, en JavaScript.

Como parte del programa acelerador de carreras de Pesto , tuve la oportunidad de contribuir a este increíble proyecto de código abierto llamado Enquirer . Le permite crear mensajes de línea de comandos con estilo que son fáciles de usar y de crear. Al momento de escribir este artículo, Enquirer tiene más de 4500 estrellas Github y es utilizado por más de 7500 repositorios.

Una de las funciones que agregué a Enquirer fue la capacidad de verificar contraseñas de un solo uso basadas en el tiempo, directamente desde la línea de comandos, generadas por cualquier aplicación de autenticación de dos factores, como Google Authenticator , sin necesidad de una conexión a Internet.


¿Por qué las OTP basadas en el tiempo?

La OTP basada en el tiempo (TOTP) es un algoritmo que tiene en cuenta el tiempo actual para generar una contraseña única de un solo uso.

En la era actual, es obvio que las contraseñas por sí solas no pueden mantener alejados a los malos. Necesita una capa adicional de seguridad, un segundo factor.

Hay muchos tipos de sistemas de autenticación de dos factores, pero para que funcionen, deben ser seguros y fáciles de usar. TOTP marca ambas casillas perfectamente.

Es seguro porque:

  • La contraseña cambia cada n número de segundos (generalmente, 30 segundos), lo que evita que los intrusos usen esa misma contraseña más adelante en el futuro si de alguna manera pueden obtenerla.
  • La contraseña puede ser generada por una aplicación en el teléfono del usuario, lo que dificulta que un atacante obtenga la contraseña, ya que el teléfono del usuario suele estar a su lado.

Es fácil de usar porque:

  • En las implementaciones de aplicaciones móviles, el usuario solo necesita iniciar la aplicación TOTP y luego ingresar el TOTP que aparece en la pantalla en la aplicación.
  • A diferencia de la mayoría de las contraseñas de un solo uso basadas en dispositivos móviles que deben recibirse a través de un mensaje de texto o Internet a través de alguna conexión inalámbrica, los TOTP no dependen de la presencia de una señal celular o una conexión de datos.

Usé Google Authenticator como aplicación móvil para verificar contraseñas de un solo uso.

Google Authenticator genera OTP basadas en el tiempo que se calculan utilizando el algoritmo especificado en RFC6238 . La aplicación también es compatible con las OTP basadas en HMAC calculadas con el algoritmo especificado en RFC4226 .

Las OTP basadas en el tiempo se basan en el algoritmo de las OTP basadas en HMAC (HOTP). En este artículo, implementaremos ambos algoritmos usando NodeJS (JavaScript).

Generando secreto

En primer lugar, tendremos que crear una clave secreta específica de la aplicación que se utilizará para verificar las OTP. Esto también se compartirá con la aplicación Google Authenticator.

La clave secreta es cómo las aplicaciones de autenticación saben qué OTP generar para una aplicación/sitio web específico. El secreto se puede generar de muchas formas y esta es una de las implementaciones.

Generaremos un búfer de datos completamente aleatorio usando el incorporado

 crypto
biblioteca NodeJS y luego codificaremos los datos en base32 usando
 hi-base32
módulo npm .

 const crypto = require ( 'crypto' ); const base32 = require ( 'hi-base32' ); function generateSecret ( length = 20 ) { const randomBuffer = crypto.randomBytes(length); return base32.encode(randomBuffer).replace( /=/g , '' ); }

Esta función devolverá una cadena aleatoria que es nuestra clave secreta.

Ingrese esto en la aplicación Google Authenticator. Verificaremos las OTP para este secreto, utilizando nuestra implementación.

Generación de OTP basadas en HMAC

Para generar HOTP necesitamos una clave secreta y un valor de contador. Ya tenemos un secreto. No necesitamos preocuparnos por el contador a partir de ahora porque proporcionaremos su valor cuando generemos TOTP.

Lo esencial
Digamos que nuestra función que genera HOTP acepta dos argumentos,

 secret
y
 counter
. Primero, decodificaremos el secreto.

 const decodedSecret = base32.decode.asBytes(secret);

Ahora vamos a crear un búfer a partir de la

 counter
valor.

 const buffer = Buffer.alloc( 8 ); for ( let i = 0 ; i < 8 ; i++) { buffer[ 7 - i] = counter & 0xff ; counter = counter >> 8 ; }

Según RFC4226 , tenemos tres pasos principales para generar un HOTP.

Paso 1: generar un valor HMAC
Google Authenticator utiliza el algoritmo SHA1 para crear HMAC. Usaremos funciones de la

 crypto
biblioteca para crear un HMAC (usando SHA1), actualice el creado anteriormente
 buffer
con esto y luego producir un valor HMAC;

 const hmac = crypto.createHmac( 'sha1' , Buffer.from(decodedSecret)); hmac.update(buffer); const hmacResult = hmac.digest();

 hmacResult
es una cadena de 20 bytes que es un valor HMAC-SHA-1.

Paso 2: truncamiento dinámico
El propósito del truncamiento dinámico es extraer un código binario dinámico de 4 bytes de un resultado HMAC-SHA-1 de 20 bytes. Estos pasos se toman directamente de RFC4226 .

 const offset = hmacValue[hmacValue.length - 1 ] & 0xf ; const code = ((hmacValue[offset] & 0x7f ) << 24 ) | ((hmacValue[offset + 1 ] & 0xff ) << 16 ) | ((hmacValue[offset + 2 ] & 0xff ) << 8 ) | (hmacValue[offset + 3 ] & 0xff );

Paso 3: Calcule el valor HOTP
Google Authenticator genera contraseñas de seis dígitos, por lo que extraeremos los primeros seis dígitos de la

 code
para obtener nuestro valor HOTP final.

 const hotp = code % ( 10 ** 6 );

Poniéndolo todo junto, la función generateHOTP se puede escribir como:

 const crypto = require ( 'crypto' ); const base32 = require ( 'hi-base32' ); function generateHOTP ( secret, counter ) { const decodedSecret = base32.decode.asBytes(secret); const buffer = Buffer.alloc( 8 ); for ( let i = 0 ; i < 8 ; i++) { buffer[ 7 - i] = counter & 0xff ; counter = counter >> 8 ; } // Step 1: Generate an HMAC-SHA-1 value const hmac = crypto.createHmac( 'sha1' , Buffer.from(decodedSecret)); hmac.update(buffer); const hmacResult = hmac.digest(); // Step 2: Generate a 4-byte string (Dynamic Truncation) const code = dynamicTruncationFn(hmacResult); // Step 3: Compute an HOTP value return code % 10 ** 6 ; } function dynamicTruncationFn ( hmacValue ) { const offset = hmacValue[hmacValue.length - 1 ] & 0xf ; return ( ((hmacValue[offset] & 0x7f ) << 24 ) | ((hmacValue[offset + 1 ] & 0xff ) << 16 ) | ((hmacValue[offset + 2 ] & 0xff ) << 8 ) | (hmacValue[offset + 3 ] & 0xff ) ); }

Tenemos una función con la que podemos generar contraseñas de un solo uso basadas en HMAC. Ahora podemos usar esta función para generar contraseñas de un solo uso basadas en el tiempo.

Generación de OTP basadas en el tiempo

El algoritmo para las OTP basadas en el tiempo simplemente usa el tiempo actual de Unix (con un paso de tiempo de 30 segundos) como el

 counter
valor en el
 generateHOTP
función.

Podemos obtener la hora actual en JavaScript usando

 Date.now()
. Pero esto devuelve el número de milisegundos transcurridos desde
 January 1, 1970, 00:00:00 UTC
. Tenemos que convertir el paso de tiempo de 1 milisegundo a paso de tiempo de 30 segundos.

 const counter = Math .floor( Date .now() / 30000 );

También aceptamos un

 window
argumento que nos ayuda a obtener el TOTP de cualquier ventana de tiempo desde la hora actual. Entonces, si queremos saber qué TOTP se generó antes de 2 minutos a partir de ahora, configuramos
 window = -4
. Esto calcula el TOTP en 4 pasos de tiempo (de 30 segundos cada uno) antes de la hora actual.

Entonces nuestro

 generateTOTP
función se puede escribir como:

 function generateTOTP ( secret, window = 0 ) { const counter = Math .floor( Date .now() / 30000 ); return generateHOTP(secret, counter + window ); }

Verificación de OTP basadas en el tiempo

Para verificar los TOTP generados en la aplicación Google Authenticator, necesitamos la clave secreta. Una vez que tenemos la clave secreta podemos usar el

 generateTOTP
función anterior y calcule el TOTP para ver si coincide o no.

A veces, es posible que, mientras un usuario escribe la OTP, pase la ventana actual de 30 segundos y la OTP que ingresó falle. Para mejorar la experiencia del usuario, no solo verificamos el TOTP generado en la ventana de paso de tiempo actual, sino también un paso antes y un paso después de la ventana actual.

 If the current time is T⁰, we'll verify the TOTP for these steps: T⁰ – 1 T⁰ T⁰ + 1

También podemos usar una ventana más amplia, pero hacerlo puede ser un riesgo para la seguridad. Si usamos una ventana de

 T⁰ ± 20
, por ejemplo, ¡esto significaría que una OTP generada hace 10 minutos todavía es válida!

Teniendo esto en cuenta, nuestro

 verifyTOTP
función se puede escribir como:

 function verifyTOTP ( token, secret, window = 1 ) { if ( Math .abs(+ window ) > 10 ) { console .error( 'Window size is too large' ); return false ; } for ( let errorWindow = - window ; errorWindow <= + window ; errorWindow++) { const totp = generateTOTP(secret, errorWindow); if (token === totp) { return true ; } } return false ; }

 token
es el TOTP de Google Authenticator. estamos invocando
 generateTOTP
función para calcular los TOTP para todas las ventanas y verificar si coincide con el token ingresado.

Esta función devuelve

 true
si el token se verifica con éxito. Esto completa la implementación de la autenticación de dos factores (TOTP) con Google Authenticator.

He eliminado algunas comprobaciones de errores para que este artículo sea sencillo. Puede encontrar el código completo en esta solicitud de extracción.

Asegúrate de consultar la biblioteca de Enquirer y colocar una estrella de Github. ¡Gracias por leer!

Hola, mi nombre es Rajat. Soy un verdadero ingeniero de software full-stack con experiencia trabajando en todo, desde parchear controladores de U-boot y Linux en C hasta lanzar productos mejor calificados en Product Hunt.