Abres el cliente de VPN, escribes la contraseña y los seis dígitos de tu autenticador vuelven como no válidos — dos veces, luego una tercera. Nada ha cambiado en la cuenta desde ayer, así que el instinto es borrar la entrada del autenticador y volver a escanearla — normalmente la reparación equivocada. Un código de un solo uso no es una segunda contraseña: la pasarela tiene que pedirlo en un paso concreto, desde una entrada registrada concreta, dentro de una ventana concreta, y la mayoría de los rechazos ocurren antes de que se comparen los dígitos. Averigua en qué paso estás antes de tocar el alta.

El orden de las solicitudes te dice en qué flujo estás

Tres formas cubren casi todo inicio de sesión en VPN que incluye un código. En la forma de dos pasos el cliente envía la contraseña, el servidor emite un desafío y el cliente vuelve a preguntar. En la forma combinada la pasarela quiere contraseña y código en un solo envío — a veces concatenados, a veces tras un separador que solo documenta el operador. En la forma de navegador el cliente no tiene ningún campo: el código va a una página web, o una aprobación push lo sustituye, y el cliente de escritorio espera el resultado.

Equivocarse de forma parece un código malo. Pega un código nuevo en un campo solo de contraseña y el servidor lo leerá como parte de la contraseña. En el lado del cliente, OpenVPN 2.4 y posteriores hacen visible la diferencia: un servidor que responde con AUTH_FAILED,CRV1: espera una respuesta al desafío, así que el perfil necesita static-challenge o un archivo de contraseña en forma SCRV1:. Un perfil más antiguo que solo lleva auth-user-pass valida la contraseña y luego se detiene, lo que en el registro parece un fallo de OTP aunque no se haya enviado ningún código.

Merece la pena nombrar WireGuard como la excepción: autentica pares de claves, no personas, así que no hay campo para un código. Si un proveedor anuncia uno, algo fuera del túnel lo acepta.

Qué hace el servidor con los seis dígitos

Los códigos basados en tiempo siguen RFC 6238, que envuelve la construcción más antigua basada en contador de RFC 4226: un HMAC sobre un factor móvil, truncado a seis dígitos por defecto. Para TOTP el factor móvil es la hora Unix actual dividida por un paso, 30 segundos salvo que el operador lo haya cambiado. El verificador nunca compara tus dígitos con un valor guardado; recalcula el código esperado a partir de la semilla compartida y normalmente acepta también los pasos vecinos, así que un viaje de ida y vuelta lento no hace fallar el inicio de sesión.

Dos consecuencias se pasan por alto. La zona horaria del teléfono es irrelevante, porque la semilla nunca ve un reloj local — solo cuenta la desviación respecto al UTC real, y un dispositivo que va dos minutos adelantado falla todos los códigos mientras muestra una cuenta atrás limpia. Y un código es de un solo uso por diseño: el verificador recuerda el último valor de contador que aceptó para esa semilla, así que los mismos dígitos enviados de nuevo se rechazan incluso dentro de la misma ventana. Un cliente que reintenta tras un tiempo de espera puede quemar el código que acaba de enviar.

Los tokens basados en contador mueven el contador con cada pulsación, así que se desincronizan después de que se hayan generado códigos que nunca se envían; la reparación habitual es una ventana de resincronización que acepta unos cuantos valores por delante. Si el operador dio de alta HOTP y tu aplicación muestra TOTP, todos los valores son incorrectos de una forma que parece un problema de reloj. La URI de aprovisionamiento detrás del código QR indica el tipo, los dígitos, el periodo y el hash.

Fallos que parecen un código incorrecto

La entrada registrada es el culpable más habitual. Las aplicaciones de autenticación etiquetan las entradas por emisor y cuenta, así que quien tiene dos identidades en la misma VPN puede acabar con dos entradas cuyas etiquetas difieren en un carácter. Un código es válido para la semilla que lo generó y para nada más. Compara la etiqueta del teléfono con el nombre de usuario que registra el servidor, no con lo que recuerdas haber escrito.

Segundo, un conjunto de parámetros que no encaja. Una semilla dada de alta con ocho dígitos, un periodo de 60 segundos o SHA-256 produce códigos que un verificador que espera seis dígitos, 30 segundos y SHA-1 rechaza, y en el cliente eso es indistinguible de un código incorrecto. Aparece tras migraciones en las que la entrada se volvió a añadir a partir de una foto del código QR, o en las que el registro del token se reconstruyó con valores por defecto.

Tercero, no va del código. Las pasarelas suelen devolver un único fallo genérico de autenticación para una contraseña incorrecta, un código caducado y una cuenta desactivada, a propósito, para que nadie pueda sondear qué factor ha fallado. Lee el registro de la pasarela o de RADIUS en lugar del mensaje del cliente: un desafío que nunca se emitió, un rechazo de acceso sin atributo OTP y una denegación por política se ven igual en pantalla y llevan a pasos siguientes distintos.

Una secuencia corta que lo acota

Empieza por la comprobación más barata y detente en el primer paso que no se cumpla.

  1. Espera un código nuevo, envíalo una vez y fíjate en si el desafío aparece antes o después de que se acepte la contraseña.
  2. Haz coincidir la etiqueta del autenticador con el nombre de usuario que guarda el servidor.
  3. Confirma que el perfil puede responder un desafío, como en el caso CRV1 de antes.
  4. Compara el reloj del dispositivo con una fuente de tiempo conocida; una desviación de más de unas decenas de segundos rompe TOTP por sí sola.
  5. Pregunta al operador si el token es TOTP o HOTP, y qué dígitos, periodo y hash se dieron de alta.

Dos reglas evitan que esto empeore. No reintentes muchas veces: muchas pasarelas cuentan los fallos por cuenta y o la bloquean o empiezan a retrasar las respuestas, así que una ráfaga convierte una pequeña configuración errónea en un ticket de soporte. Y no vuelvas a dar de alta el token como diagnóstico, porque invalida la semilla antigua; si el fallo real era un desafío que el cliente nunca envió, ahora tienes dos cambios que razonar en lugar de uno.

Mantén la semilla y los códigos de recuperación fuera del circuito

Los seis dígitos y el secreto que hay detrás no son intercambiables. Un código QR de aprovisionamiento o una semilla Base32 genera todos los códigos futuros de la cuenta, así que pertenece a la misma categoría que la contraseña: no en una captura de pantalla, no en un comentario de un ticket, no en un chat con alguien que se puso en contacto contigo primero. Los códigos de recuperación son un mecanismo aparte — de un solo uso, a menudo se saltan la petición de código por completo, y gastar uno para probar la cuenta elimina una alternativa que puedes necesitar más adelante.

Un código tampoco hace fiable una página de inicio de sesión: una petición de OTP en un dominio de aspecto similar recoge un código válido y lo reproduce dentro de la ventana, y el certificado sigue siendo lo que te dice dónde escribes.

Si la secuencia acaba en un perfil que no puede responder un desafío, arregla el perfil y vuelve a probar con un código nuevo. Si acaba en parámetros de alta que no encajan, pide al operador que lea el registro del token antes de que nadie escanee nada. Si acaba en un bloqueo, espera a que pase en lugar de cambiar de cliente — el estado de la cuenta es el obstáculo, no la aplicación.

Artículos relacionados