Denegación de servicio
El formulario de registro tiene un campo de nombre. Nada impide que un nombre tenga diez millones de caracteres.
// Lo que se envía como `name`
'a'.repeat(10_000_000)Nada en esa cadena es código. No se va a interpretar como nada en particular. Simplemente es enorme, y resulta que con ser enorme basta.
Guárdalo y la base de datos crece. Consúltalo y la consulta se vuelve lenta. Respáldalo y el respaldo también crece, cada noche, para siempre. Repite eso unas cuantas miles de veces y el servicio deja de poder responderle a nadie.
Una solicitud no tiene que ser ingeniosa para hacer daño. Solo tiene que ser costosa.
Envía esto solo contra tu propio servicio
Las pruebas de volumen son indistinguibles de un ataque mientras están corriendo, y afectan a todos los demás usuarios de aquello contra lo que se dirijan. Úsalas solo en tu propia infraestructura o en un sistema para el que tengas permiso explícito de hacer pruebas.
La disponibilidad es una propiedad de seguridad
La seguridad suele discutirse en términos de mantener secretos y mantener los datos correctos. Existe una tercera propiedad, y este capítulo trata de ella: la disponibilidad, es decir, si el servicio responde o no.
Un ataque de denegación de servicio, DoS por sus siglas en inglés, va tras esa tercera propiedad. No lee nada, no cambia nada ni roba nada. Lo que hace es dejar al servicio incapaz de cumplir su función, lo cual para un negocio suele ser el resultado más costoso.
Piensa en lo que pierde una tienda el día que no puede abrir. Ahí tampoco se robó nada.
Cuatro formas en que un servicio cae
El curso agrupa estos ataques según qué explota el atacante, y vale la pena mantener esa clasificación porque cada uno se combate de manera distinta.
| Forma | Cómo funciona | Qué agota |
|---|---|---|
| Bala mágica | Un solo mensaje construido con precisión que viola una regla del protocolo, como enviar más datos de los que un campo fue diseñado para contener | Un defecto específico, de inmediato |
| Basado en volumen | Suficiente tráfico o una entrada lo bastante grande como para saturar la conexión o llenar el disco | Ancho de banda, memoria, almacenamiento |
| De protocolo | Abuso de cómo está especificado el funcionamiento de un protocolo, de modo que el servidor retiene recursos que nunca llega a liberar | Tablas de conexión, temporizadores, sockets |
| Distribuido | El mismo tráfico, pero llegando desde miles de máquinas distintas a la vez | Todo lo anterior, desde todas partes |
Vale la pena ver en detalle el de protocolo, porque muestra qué tan poco tráfico necesita un ataque efectivo. Una conexión TCP, el apretón de manos que subyace a la mayoría del tráfico de internet, se abre en tres pasos:
- El cliente envía un paquete
SYN, que significa "quisiera conectarme". - El servidor responde con
SYN-ACK, que significa "adelante", y empieza a mantener un espacio reservado mientras espera. - El cliente responde con
ACK, y la conexión queda establecida.
En una inundación SYN, el atacante envía el primer paso con una dirección de retorno falsificada. El segundo paso va a dirigirse a una máquina que nunca lo pidió y que no tiene nada que responder. El tercer paso nunca llega.
El servidor mantiene un espacio abierto y un temporizador corriendo, mientras el atacante ya pasó a la siguiente dirección falsificada.
Nada de esto implica un volumen alto. Es barato para quien lo envía y costoso para quien lo recibe, una y otra vez, hasta que la tabla de conexiones se llena y un visitante real no consigue un espacio.
Una denegación de servicio distribuida, o DDoS, es cualquiera de estos ataques proveniente de una botnet: una red de máquinas comunes controladas por el atacante, normalmente infectadas sin que sus dueños se den cuenta.
Eso es lo que lo hace difícil de combatir. Cada máquina es un dispositivo real que hace solicitudes que parecen legítimas, así que no hay una sola dirección que bloquear ni una firma que filtrar.
Un apretón de manos falsificado cuesta un solo paquete de enviar y bloquea un espacio durante segundos. Ese desequilibrio es todo el juego, y por eso el volumen no es lo único que hay que vigilar.
Las defensas se combinan
Aquí no existe un control único. El curso enumera seis, y están ubicados a propósito en capas distintas:
- Redundancia. Ten más de uno de todo: servidores, centros de datos, rutas de red, servidores de nombres. La regla general es tres, para que uno pueda estar fallando y otro bajo ataque mientras un tercero sigue funcionando.
- Limitación y regulación de tasa. La limitación de tasa (rate limiting) rechaza las solicitudes que superan un tope. La regulación (throttling) las ralentiza. Cien llamadas a la API por minuto, cinco intentos de inicio de sesión en diez minutos, un megabyte por segundo.
- Filtrado. Decide qué aceptar y desde dónde. Bloquea direcciones o regiones, rechaza solicitudes con cargas útiles obviamente maliciosas, exige autenticación, revisa los encabezados.
- Endurecimiento (hardening). Elimina lo que no necesitas. Cada servicio en ejecución es una puerta de entrada, y también lo es cada cuenta que nadie usa: logins de administrador por defecto, personas que se fueron y conservaron el acceso, permisos otorgados una sola vez para una migración.
- Aplicación de parches. El ataque de bala mágica depende de un defecto específico y conocido. Aplicar la corrección del proveedor es lo que lo elimina.
- Monitoreo. No puedes detectar lo anormal sin conocer lo normal. Un servicio que normalmente recibe mil solicitudes por hora y de pronto recibe cien mil solo es obviamente anómalo si alguien registró ese dato de las mil.
Para el caso específico del nombre de diez millones de caracteres, la solución es un límite de longitud, verificado en el servidor antes de guardar el valor. Eso es validación de esquemas, y es la capa hacia la que apunta esta sección.
La redundancia te da tiempo. Los límites de tasa acotan el daño. El monitoreo es cómo te enteras. La aplicación de parches elimina el hueco específico. Cada una cubre un momento distinto, así que conviene tenerlas todas en lugar de apostar por la mejor.
Ponlo a prueba
El formulario de registro acepta name, email y password, los guarda, y devuelve los dos primeros. No hay límites en ningún lado.
Resuelve estas tres cosas:
- ¿Qué solicitud individual le cuesta más al servidor, y qué la hace costosa?
- ¿Cuáles de las seis defensas detendrían esa solicitud, y cuáles solo reducirían el daño?
- ¿Cuál es el cambio más barato que cierra esa brecha?
Compara tus respuestas
1. La solicitud más costosa. Un name o password muy largo. Cuesta memoria al procesarlo, almacenamiento al guardarlo, tiempo en cada consulta que toque esa fila, y espacio en cada respaldo a partir de entonces.
password es el peor de los dos si la aplicación lo hashea. El hasheo es deliberadamente lento, así que un valor enorme convierte una operación costosa en una mucho más costosa todavía.
2. Qué defensas hacen efecto.
- La detienen por completo: el filtrado y un límite de longitud. El servidor rechaza la solicitud antes de hacer el trabajo costoso.
- Reducen el daño: la limitación y la regulación de tasa. Acotan qué tan seguido se repite, pero la solicitud individual de todas formas llega.
- Ninguna de las dos cosas: la redundancia, la aplicación de parches y el monitoreo. Te ayudan a sobrevivirlo, eliminan huecos no relacionados, y te permiten enterarte de que está pasando.
3. El cambio más barato. Una longitud máxima en cada campo de texto, aplicada en el servidor. Es una línea por campo en un esquema y elimina toda la categoría de problema, por eso la sección dedica sus capítulos restantes a lograr que ese esquema quede bien hecho.
Hacia dónde va esto ahora
Dos capítulos después, y ambos bugs vienen de un mismo paso que faltó. Nada verificó lo que llegaba antes de que la aplicación actuara sobre ello.
Inyección SQL es el tercero y el más directo. Entradas que ya no solo se guardan en la base de datos, sino que le dicen qué hacer.

