Saltar al contenido
nvíame
Capítulo 3 de 412 min24 sep 2026

Rate limiting y expiración

Defiende tu flujo de OTP contra fuerza bruta y contra el fraude de tráfico.

Un OTP de 6 dígitos tiene un millón de combinaciones. Sin límite de intentos, un atacante lo adivina en minutos. Sin límite de emisión, alguien puede usar tu formulario para enviar miles de SMS a tu costo.

Límites recomendados

  • Expiración: 5 a 10 minutos.
  • Intentos de verificación: 5 por código; luego invalidar.
  • Emisiones: 3 por número cada 15 minutos; reenvío con espera creciente (30 s, 60 s, 120 s).
  • Por IP y por prefijo: límites globales para detectar ataques distribuidos.
async function verify(phone, input) {
  const rec = await store.get(phone);
  if (!rec || Date.now() > rec.exp) return { ok: false, reason: "expired" };
  if (rec.attempts >= 5) return { ok: false, reason: "locked" };
  rec.attempts++;
  const ok = safeEqual(rec.hash, await sha256(phone + ":" + input));
  if (ok) await store.delete(phone); else await store.set(phone, rec);
  return { ok };
}

Un código de seis dígitos tiene un millón de combinaciones. Sin límite de intentos, un atacante automatizado lo adivina en minutos. Con cinco intentos por código y expiración de cinco minutos, la probabilidad de acertar cae a cinco en un millón por emisión.

Limita en dos ejes: intentos de verificación por código y emisiones por número y por IP. El segundo eje te protege del SMS pumping, un fraude en el que bots disparan miles de OTP hacia números premium para cobrar comisiones.

Pruébalo

// Lock the code after 3 failed attempts
const phone = "+56912345678";
const intentos = {};

function verificar(code) {
  intentos[phone] = (intentos[phone] || 0) + 1;
  if (intentos[phone] > 3) {
    console.error("Bloqueado: demasiados intentos. Solicita un código nuevo.");
    return false;
  }
  return mx.otp.verify(phone, code);
}

const real = mx.otp.issue(phone);
verificar("000000");
verificar("123456");
verificar("999999");
const ok = verificar(real); // fourth attempt: locked even with the right code
console.log("acceso concedido:", ok);
Se completa automáticamente al leer el 80%.

Comentarios (3)

Valentina Muñoz24 sep 2026

¿Qué es el fraude de tráfico (SMS pumping)?

Equipo nvíameAutor24 sep 2026

Bots que disparan OTP a números premium controlados por el atacante, que cobra una parte de la terminación. Se mitiga con límites por IP, por prefijo y por país, y con CAPTCHA ante picos.

Joaquín Vega24 sep 2026

Lo apliqué en el proyecto del trabajo. La sección «Rate limiting y expiración» me ahorró una discusión larga con el equipo: ahora tenemos un criterio compartido.

Matías Herrera24 sep 2026

¿Hay alguna diferencia importante si lo implemento en un servicio con varias instancias detrás de un balanceador?

Equipo nvíameAutor24 sep 2026

Sí: todo estado que hoy vive en memoria (contadores, sesiones, claves vistas) debe moverse a un almacén compartido con TTL, como Redis. Si no, cada instancia ve solo una parte de la historia.

Los comentarios se guardan solo en este navegador.