¿Qué es un ataque de fuerza bruta y cómo protegerte?

Un ataque de fuerza bruta es el intento automatizado de adivinar contraseñas, claves o tokens probando muchas combinaciones hasta que una funcione. Límite de intentos, contraseñas largas con hash lento y MFA son las defensas principales.

Actualizado el 7 min de lectura

Objetivos de aprendizaje

Después de leer este artículo podrás:

  • Entender cómo funciona un ataque de fuerza bruta y sus variantes
  • Distinguir ataques online, offline, password spraying y credential stuffing
  • Proteger un login y un servidor SSH con límite de intentos, hash y MFA
En esta página

Basta poner un formulario de login o un servidor SSH en internet para que los logs muestren intentos de acceso que tú no hiciste. Casi siempre son robots probando combinaciones de usuario y contraseña, sin prisa y sin parar. Es el ataque más antiguo y simple que existe, y sigue funcionando porque todavía quedan muchas puertas abiertas.

Saber cómo funciona te dice dónde poner cada defensa: por qué algunas variantes aciertan en segundos y otras nunca terminan, y qué puedes aplicar hoy en tu login y en tu servidor SSH.

123456 · qwerty · adminlista de contraseñas filtradasAtacanterobotLímite por IPfrena el exceso de una direcciónLímite por cuentafrena intentos desde varias IPHash lentofrena a quien tiene hashes filtradosMFAla contraseña correcta no bastaFormulario de loginningún intento entró
Ninguna defensa basta sola: cada capa frena parte de los intentos, y juntas cierran el login.

¿Qué es un ataque de fuerza bruta?#

Es el intento de descubrir un secreto (contraseña, PIN, clave de API, token) probando posibilidades en masa hasta que una funcione. No explota un fallo del código: explota el hecho de que el secreto se puede adivinar en un tiempo viable.

MITRE ATT&CK, el catálogo de técnicas de ataque que usan los equipos de seguridad en todo el mundo, registra la fuerza bruta como la técnica T1110, usada para acceder a cuentas cuando la contraseña es desconocida o cuando el atacante ya tiene los hashes. Tiene cuatro subtécnicas:

  • Adivinación de contraseñas (T1110.001): muchas contraseñas contra una cuenta, normalmente a partir de listas de contraseñas comunes.
  • Descifrado de contraseñas (T1110.002): el atacante ya tiene los hashes, por ejemplo de una base filtrada, y prueba contraseñas en su propia máquina.
  • Password spraying (T1110.003): pocas contraseñas muy comunes contra muchas cuentas, para no activar el bloqueo por cuenta.
  • Credential stuffing (T1110.004): pares de correo y contraseña filtrados de otro sitio, probados en el tuyo. Funciona porque mucha gente repite la contraseña.

¿Cómo funciona el ataque en la práctica?#

Un ataque online apunta a tu sistema en producción: el robot envía una petición de login por intento y lee la respuesta. Cada intento cuesta un viaje de ida y vuelta por la red, y puedes contarlos y frenarlos.

Un ataque offline ocurre después de una filtración. Con los hashes en la mano, el atacante prueba contraseñas en su propia máquina, sin límite de intentos y sin que tú lo veas. Ahí la única barrera es el algoritmo de hash: cuanto más lento es y más memoria exige, menos contraseñas por segundo puede probar el atacante.

La cuenta del espacio de búsqueda muestra por qué importa la longitud. Una contraseña de 8 letras minúsculas tiene 26^8, unos 209 mil millones de combinaciones. Una de 15 caracteres con el mismo alfabeto tiene 26^15, unas 1,7 x 10^21. Cada carácter extra multiplica el trabajo por 26. Pero los atacantes rara vez prueban todo: empiezan por listas de contraseñas filtradas, así que una contraseña larga que ya se filtró cae en segundos.

¿Dónde ocurren los ataques de fuerza bruta?#

  • Formularios de login de sitios, paneles y APIs.
  • SSH, RDP y FTP expuestos a internet con autenticación por contraseña.
  • Paneles de administración en rutas conocidas, como /wp-admin o /admin.
  • Endpoints de restablecimiento de contraseña y verificación de códigos de 6 dígitos, que tienen solo 1 millón de combinaciones.
  • Claves y tokens cortos o predecibles. Una clave de API larga y aleatoria no se adivina; una que se filtró en GitHub ni siquiera hace falta adivinarla, como muestra clave de API expuesta en GitHub.

¿Cómo proteger un formulario de login?#

Las defensas funcionan en capas, y ninguna resuelve el problema sola.

  1. Límite de intentos por IP y por cuenta. OWASP recomienda asociar el contador a la cuenta, no solo a la IP, porque el atacante cambia de dirección. El NIST SP 800-63B-4 exige limitar los fallos consecutivos a no más de 100 por cuenta.
  2. Mensaje genérico. Responde "correo o contraseña inválidos" en ambos casos. Mensajes distintos, códigos HTTP distintos o tiempos de respuesta distintos revelan qué cuentas existen.
  3. Hash lento. Guarda las contraseñas con Argon2id. OWASP recomienda como mínimo 19 MiB de memoria, 2 iteraciones y paralelismo 1; scrypt y bcrypt (factor de costo 10 o más) son alternativas.
  4. Contraseñas largas, sin reglas de composición. El NIST pide un mínimo de 15 caracteres para una contraseña usada como único factor (8 con MFA), una lista de bloqueo de contraseñas comunes y filtradas, y no obligar a cambios periódicos sin indicios de filtración.
  5. MFA. Es la defensa más fuerte: incluso con la contraseña correcta, el atacante se detiene en el segundo factor.
  6. CAPTCHA después de algunos fallos. OWASP lo trata como defensa en profundidad que encarece el ataque, no como barrera definitiva.

Un ejemplo en Node.js con Express 5, express-rate-limit 8 y argon2, con límite por IP y por cuenta:

js
// npm install express@5 express-rate-limit@8 argon2
import argon2 from "argon2";
import express from "express";
import { rateLimit } from "express-rate-limit";

const app = express();
app.set("trust proxy", 1); // detrás de un proxy inverso, usa la IP real del cliente
app.use(express.json());

const tooMany = { error: "Demasiados intentos. Inténtalo de nuevo más tarde." };

// Por IP: hasta 20 intentos fallidos cada 15 minutos
const ipLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  limit: 20,
  skipSuccessfulRequests: true,
  standardHeaders: "draft-8",
  legacyHeaders: false,
  message: tooMany,
});

// Por cuenta: hasta 5 intentos fallidos cada 15 minutos, vengan de donde vengan
const accountLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  limit: 5,
  skipSuccessfulRequests: true,
  keyGenerator: (req) => String(req.body?.email ?? "").toLowerCase(),
  standardHeaders: "draft-8",
  legacyHeaders: false,
  message: tooMany,
});

// Solo de ejemplo: en producción, los hashes vienen de la base de datos
const users = new Map([
  ["ana@example.com", await argon2.hash("una frase de contraseña larga de ejemplo")],
]);
// Hash usado cuando el correo no existe, para que el tiempo de respuesta no delate cuentas
const dummyHash = await argon2.hash("cuenta-inexistente");

app.post("/login", ipLimiter, accountLimiter, async (req, res) => {
  const { email, password } = req.body ?? {};
  if (typeof email !== "string" || typeof password !== "string") {
    return res.status(400).json({ error: "Solicitud inválida" });
  }
  const hash = users.get(email.toLowerCase());
  const valid = await argon2.verify(hash ?? dummyHash, password);
  if (!hash || !valid) {
    // el mismo mensaje para un correo inexistente y una contraseña incorrecta
    return res.status(401).json({ error: "Correo o contraseña inválidos" });
  }
  res.json({ ok: true });
});

app.listen(Number(process.env.PORT) || 3000);

skipSuccessfulRequests hace que solo cuenten los fallos. Después de cinco fallos para la misma cuenta, el siguiente intento recibe 429 Too Many Requests hasta que termine la ventana de 15 minutos. argon2.hash usa Argon2id por defecto, con parámetros por encima del mínimo de OWASP. En un servidor con varias instancias, cambia el almacenamiento en memoria del limitador por uno compartido, como Redis.

¿Cómo proteger un servidor SSH?#

La defensa más eficaz es eliminar la contraseña. Con claves SSH no hay nada que adivinar; mira qué son las claves SSH. En /etc/ssh/sshd_config, después de confirmar que el login con clave funciona:

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

Reinicia el servicio SSH y prueba desde una segunda sesión antes de cerrar la actual. Para cortar el ruido de los robots, fail2ban lee los logs y bloquea las IP con fallos repetidos. Los valores por defecto de jail.conf son 5 fallos (maxretry) en 10 minutos (findtime) para 10 minutos de bloqueo (bantime). Un /etc/fail2ban/jail.local que amplía el bloqueo:

ini
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h

¿Cuáles son los límites de estas defensas?#

El bloqueo por cuenta tiene un efecto secundario: un atacante puede fallar la contraseña a propósito para bloquear la cuenta de otra persona. OWASP sugiere bloqueos cortos y crecientes y dejar disponible el flujo de "olvidé mi contraseña" incluso durante el bloqueo.

Un límite solo por IP no frena ataques distribuidos, y los CAPTCHA pueden resolverse con servicios de pago. Ninguna de estas defensas ayuda si la contraseña ya se filtró y el usuario la repite en otros sitios; contra eso, solo sirven la MFA y las listas de bloqueo de contraseñas filtradas.

La fuerza bruta tampoco es lo mismo que un DDoS. Los dos generan muchas peticiones, pero el DDoS quiere tumbar el servicio y la fuerza bruta quiere entrar en él. Un WAF puede ayudar a filtrar tráfico automatizado, pero cuántos intentos de login acepta cada cuenta es una regla de tu código. Para el resto de la protección, usa el checklist de seguridad para deploy.

Cómo hacerlo en Square Cloud#

En Square Cloud, la parte del SSH queda fuera: la aplicación solo recibe tráfico entrante en el puerto 80, publicado por HTTPS, así que no hay un servidor SSH tuyo expuesto para que los robots prueben contraseñas. Lo que queda es el formulario de login, y ahí las capas se reparten. La red delante de tus aplicaciones tiene WAF y mitigación de DDoS en las capas L3, L4 y L7 en todos los planes, lo que filtra el tráfico de red; el límite de intentos, el hash lento y la MFA siguen en tu código, como en el ejemplo de arriba.

Si sirves el mismo dominio con load balancing (desde el plan Standard), cada aplicación tendría su propio contador en memoria, y el atacante ganaría intentos extra por cada instancia. Como no hay sticky session, cambia el almacenamiento de express-rate-limit por uno compartido: el hospedaje de Redis, también desde Standard, está en el mismo datacenter que las aplicaciones. Guarda la URL de Redis y los secretos de sesión en variables de entorno de la aplicación, nunca en el código; el cambio se aplica en el siguiente reinicio.

Para ver el ataque, el analytics web incluido en todos los planes muestra rutas y status codes: un salto de respuestas 401 y 429 es la señal. Mira la protección en la página de red, configura los secretos en variables de entorno y conoce el hospedaje de Redis.

Infraestructura

Mitigación de DDoS L3/L4/L7 y WAF en todos los planes

Más información

Preguntas frecuentes

¿Cuánto tarda un ataque de fuerza bruta?

Depende del tamaño del espacio de contraseñas y de la velocidad de prueba. Online, con límite de intentos, una contraseña larga que no esté en listas filtradas queda fuera de alcance. Offline, contra una base de hashes filtrada, lo que frena al atacante es el hash lento (Argon2id, scrypt, bcrypt).

¿La fuerza bruta es delito?

Intentar acceder a un sistema o cuenta ajenos sin autorización es delito en muchos países. Prueba solo sistemas tuyos o con autorización por escrito.

¿Bloquear la IP después de algunos fallos lo resuelve?

Ayuda, pero no basta. Los ataques distribuidos usan miles de IP, por eso OWASP recomienda contar los fallos también por cuenta. El cuidado está en no permitir que un atacante bloquee cuentas legítimas a propósito.

¿Cuál es la defensa más eficaz contra la fuerza bruta?

La autenticación multifactor (MFA). OWASP cita un análisis de Microsoft según el cual la MFA habría evitado el 99,9% de los casos de cuentas comprometidas. Combínala con límite de intentos y contraseñas largas.

Siguiente artículoHackearon mi aplicación: qué hacer ahoraSi hackearon tu aplicación, contén el acceso, cambia todos los secretos y conserva los logs antes de limpiar. El orden correcto, cómo hallar la causa y cómo volver.

Más en Seguridad

Ver los 10 artículos