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 , tuve la oportunidad de contribuir a este increíble proyecto de código abierto llamado . 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. de carreras de Pesto Enquirer Una de las funciones que agregué a Enquirer fue la capacidad de , sin necesidad de una conexión a Internet. 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 ¿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 . La aplicación también es compatible con las OTP basadas en HMAC calculadas con el algoritmo especificado en . RFC6238 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 biblioteca NodeJS y luego codificaremos los datos en base32 usando . crypto hi-base32 módulo npm crypto = ( ); base32 = ( ); { randomBuffer = crypto.randomBytes(length); base32.encode(randomBuffer).replace( , ); } const require 'crypto' const require 'hi-base32' ( ) function generateSecret length = 20 const return /=/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. Digamos que nuestra función que genera HOTP acepta dos argumentos, y . Primero, decodificaremos el secreto. Lo esencial secret counter decodedSecret = base32.decode.asBytes(secret); const Ahora vamos a crear un búfer a partir de la valor. counter buffer = Buffer.alloc( ); ( i = ; i < ; i++) { buffer[ - i] = counter & ; counter = counter >> ; } const 8 for let 0 8 7 0xff 8 Según , tenemos tres pasos principales para generar un HOTP. RFC4226 Google Authenticator utiliza el algoritmo SHA1 para crear HMAC. Usaremos funciones de la biblioteca para crear un HMAC (usando SHA1), actualice el creado anteriormente con esto y luego producir un valor HMAC; Paso 1: generar un valor HMAC crypto buffer hmac = crypto.createHmac( , Buffer.from(decodedSecret)); hmac.update(buffer); hmacResult = hmac.digest(); const 'sha1' const es una cadena de 20 bytes que es un valor HMAC-SHA-1. hmacResult 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 . Paso 2: truncamiento dinámico RFC4226 offset = hmacValue[hmacValue.length - ] & ; code = ((hmacValue[offset] & ) << ) | ((hmacValue[offset + ] & ) << ) | ((hmacValue[offset + ] & ) << ) | (hmacValue[offset + ] & ); const 1 0xf const 0x7f 24 1 0xff 16 2 0xff 8 3 0xff Google Authenticator genera contraseñas de seis dígitos, por lo que extraeremos los primeros seis dígitos de la para obtener nuestro valor HOTP final. Paso 3: Calcule el valor HOTP code hotp = code % ( ** ); const 10 6 Poniéndolo todo junto, la función generateHOTP se puede escribir como: crypto = ( ); base32 = ( ); { decodedSecret = base32.decode.asBytes(secret); buffer = Buffer.alloc( ); ( i = ; i < ; i++) { buffer[ - i] = counter & ; counter = counter >> ; } hmac = crypto.createHmac( , Buffer.from(decodedSecret)); hmac.update(buffer); hmacResult = hmac.digest(); code = dynamicTruncationFn(hmacResult); code % ** ; } { offset = hmacValue[hmacValue.length - ] & ; ( ((hmacValue[offset] & ) << ) | ((hmacValue[offset + ] & ) << ) | ((hmacValue[offset + ] & ) << ) | (hmacValue[offset + ] & ) ); } const require 'crypto' const require 'hi-base32' ( ) function generateHOTP secret, counter const const 8 for let 0 8 7 0xff 8 // Step 1: Generate an HMAC-SHA-1 value const 'sha1' const // Step 2: Generate a 4-byte string (Dynamic Truncation) const // Step 3: Compute an HOTP value return 10 6 ( ) function dynamicTruncationFn hmacValue const 1 0xf return 0x7f 24 1 0xff 16 2 0xff 8 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 (con un paso de tiempo de 30 segundos) como el valor en el función. tiempo actual de Unix counter generateHOTP Podemos obtener la hora actual en JavaScript usando . Pero esto devuelve el número de milisegundos transcurridos desde . Tenemos que convertir el paso de tiempo de 1 milisegundo a paso de tiempo de 30 segundos. Date.now() January 1, 1970, 00:00:00 UTC counter = .floor( .now() / ); const Math Date 30000 También aceptamos un 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 . Esto calcula el TOTP en 4 pasos de tiempo (de 30 segundos cada uno) antes de la hora actual. window window = -4 Entonces nuestro función se puede escribir como: generateTOTP { counter = .floor( .now() / ); generateHOTP(secret, counter + ); } ( ) function generateTOTP secret, window = 0 const Math Date 30000 return 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 función anterior y calcule el TOTP para ver si coincide o no. generateTOTP 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 función se puede escribir como: verifyTOTP { ( .abs(+ ) > ) { .error( ); ; } ( errorWindow = - ; errorWindow <= + ; errorWindow++) { totp = generateTOTP(secret, errorWindow); (token === totp) { ; } } ; } ( ) function verifyTOTP token, secret, window = 1 if Math window 10 console 'Window size is too large' return false for let window window const if return true return false es el TOTP de Google Authenticator. estamos invocando función para calcular los TOTP para todas las ventanas y verificar si coincide con el token ingresado. token generateTOTP Esta función devuelve si el token se verifica con éxito. Esto completa la implementación de la autenticación de dos factores (TOTP) con Google Authenticator. true He eliminado algunas comprobaciones de errores para que este artículo sea sencillo. Puede encontrar el código completo en esta de extracción. solicitud Asegúrate de consultar la biblioteca de y colocar una estrella de Github. ¡Gracias por leer! Enquirer 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.