Skip to content
This page has been auto-translated and may contain errors.View in English

Fundamentos de rate limiting

Un solo cliente puede hacer mil solicitudes por segundo. Nada en HTTP se lo impide, y tu servidor va a intentar responder cada una.

El rate limiting controla cuánto tráfico acepta un servicio. Es la diferencia entre un endpoint que sobrevive a una mala tarde y uno que se cae porque un solo script se entusiasmó de más.

Tres problemas que resuelve

Uso justo. Si un cliente acapara los recursos, todos los demás esperan. Un límite evita que un solo cliente consuma lo que necesita toda la base de usuarios, así el tráfico legítimo sigue recibiendo respuesta mientras se rechaza el bucle descontrolado de alguien más.

Seguridad. Un endpoint de login sin límite es una invitación a adivinar contraseñas, miles a la vez. Los límites hacen que la fuerza bruta sea tan lenta que se vuelve inútil, y frenan los ataques de denegación de servicio más simples.

Recursos. La sobrecarga vuelve lento un servicio antes de dejarlo inaccesible, y es la lentitud lo que hace que los usuarios se vayan. Limitar el rendimiento mantiene los tiempos de respuesta predecibles para todos los que siguen dentro del límite.

Los límites no son, por sí solos, una defensa contra DDoS

Un ataque de denegación de servicio distribuido llega desde miles de máquinas separadas, cada una pareciendo un cliente normal. Los límites por dirección apenas hacen mella en eso.

Responder a eso requiere algo por encima: filtrado geográfico, análisis de comportamiento, o un proveedor que se ponga delante de ti. El rate limiting es una capa, no la solución completa.

JunoTres problemas que resuelve Los tres se solapan, por eso un solo control los cubre todos. Uso justo, seguridad y protección de recursos son el mismo mecanismo visto desde distintos ángulos.

Limitar cuántas veces puede preguntar cualquiera es lo que hace que una app sea difícil de abusar y agradable para todos los demás al mismo tiempo.

JunoTres problemas que resuelve Los límites que conviene fijar primero por lo general no son los globales. Un endpoint de login, un restablecimiento de contraseña, un registro, una búsqueda que golpea fuerte la base de datos: esos quieren su propio límite estricto, mucho antes de un tope general sobre todo.

La pregunta útil para cada endpoint es qué podría hacer plausiblemente un usuario legítimo en un minuto, y luego dejar margen por encima de eso.

JunoTres problemas que resuelve El rate limiting en el login tiene un matiz que vale la pena conocer: limitar por dirección castiga a toda una oficina que comparte una sola dirección, mientras que limitar por nombre de usuario le permite a un atacante bloquear cualquier cuenta que elija fallando su login a propósito.

El enfoque que funciona es limitar ambas cosas, con presupuestos distintos, y nunca bloquear una cuenta directamente solo por fallos. Frenar las respuestas funciona mejor que bloquear en este caso, porque le cuesta tiempo al atacante sin causarle una denegación de servicio a tus propios usuarios.

Rechazar versus frenar

Dos controles relacionados que se usan indistintamente y se comportan de manera distinta.

Rate limitingThrottling
Qué haceRechaza solicitudes que superan un límiteFrena las solicitudes a medida que se acerca el límite
Qué ve el clienteUn error, normalmente 429 Too Many RequestsUna respuesta, más tarde de lo normal
Mejor paraTopes duros que quieres hacer cumplirSuavizar picos de tráfico sin romper a los clientes

El rate limiting rechaza al superar un límite. El throttling frena.

Ambos tienen su lugar, y se combinan: frenar las cosas a medida que sube el tráfico, rechazar directamente al superar un tope duro. Throttling cubre la segunda mitad en detalle.

JunoRechazar versus frenar Una forma útil de recordar la diferencia: rechazar dice no, y frenar dice todavía no tan rápido.

Uno rompe la solicitud del cliente. El otro lo hace esperar. Cuál es más amable depende por completo de quién llama y por qué.

JunoRechazar versus frenar El throttling es más amigable con un cliente bien portado que pidió demasiado por un momento, porque su solicitud igual termina teniendo éxito. Es peor contra el abuso, ya que mantener solicitudes abiertas te cuesta conexiones y memoria.

Así que el arreglo habitual es frenar la parte intermedia y rechazar en el extremo superior: suave para clientes que se pasan un poco, firme para cualquiera que se pase mucho.

JunoRechazar versus frenar Un 429 solo es útil si el cliente puede actuar en consecuencia, lo cual significa Retry-After, más los encabezados RateLimit que le indican el límite, cuánto queda y cuándo se reinicia. Sin eso, la única estrategia del cliente es reintentar de inmediato, que es justo lo que intentabas evitar.

El modo de falla contra el que hay que diseñar es la tormenta de reintentos: todos rechazados en el mismo instante, todos reintentando en el mismo instante. El jitter en el retroceso del cliente y los reinicios escalonados son lo que evita eso, y ninguno de los dos ocurre por accidente.

Contra qué se cuenta un límite

Un límite necesita algo contra qué contar. Cuatro candidatos, cada uno con distintas ventajas y desventajas:

  • Dirección IP. Disponible en toda solicitud, incluso las anónimas, y compartida por todos los que están detrás de una red de oficina o un operador móvil.
  • ID de usuario autenticado. Preciso y justo, pero solo existe después del login.
  • Clave de API. Ideal para clientes automatizados, ya que una clave identifica exactamente a quien llama.
  • Un claim dentro de un JWT. Útil cuando la identidad ya viaja en el token.

Identificar clientes consiste en elegir entre estas opciones. En resumen: el tráfico anónimo te deja solo con la dirección, y todo lo demás es mejor cuando está disponible.

Los límites también necesitan una ventana de tiempo. Por segundo, por minuto, por hora, y esa elección moldea el comportamiento tanto como el número mismo.

JunoContra qué se cuenta un límite "Cien solicitudes" no significa nada sin dos cosas más: cien por cada cuánto, y cien de parte de quién.

Todo límite de tasa es esas tres decisiones juntas, y cambiar cualquiera de ellas cambia lo que el límite realmente hace.

JunoContra qué se cuenta un límite La duración de la ventana importa más de lo que la gente espera. Cien por hora y dos por minuto dan el mismo promedio y se comportan de forma totalmente distinta: el primero permite cien solicitudes en un segundo y luego silencio, el segundo nunca permite ningún pico.

Las ventanas cortas suavizan el tráfico. Las ventanas largas toleran picos. Elige según el tráfico que realmente quieres permitir.

JunoContra qué se cuenta un límite Cualquier cosa contra la que cuentes se vuelve algo que un atacante puede rotar. Las direcciones salen baratas de los pools de proxies residenciales; las cuentas gratuitas son baratas a menos que el registro esté protegido de por sí; las claves de API son la excepción, ya que emitir una es un acto deliberado.

Ese es el límite honesto de este control: hace que el abuso salga caro en vez de imposible, y el precio lo fija cuán difícil es conseguir tu identificador más barato.

También vale la pena decidir desde temprano dónde vive el propio estado del limitador. Los contadores en proceso son simples y se vuelven un error en cuanto corres dos instancias, porque cada una lleva su propio conteo y el límite efectivo se duplica.

Ponlo a prueba

Una API tiene un solo límite: 1000 solicitudes por hora por dirección IP. Averigua qué es lo que no logra prevenir.

  1. Un usuario en la red de una universidad no puede usar la app durante el período de clases. ¿Por qué?
  2. Un atacante quiere hacer 10 000 solicitudes por hora. ¿Cuánto le cuesta eso?
  3. Un script envía las 1000 solicitudes en los primeros dos segundos de cada hora. ¿Eso está dentro del límite?
Compara tus respuestas

1. El límite cuenta la cosa equivocada. Todos en esa red comparten una sola dirección de salida, así que miles de personas terminan compartiendo un presupuesto de mil. La solución es contar por usuario autenticado cuando exista un usuario, y dejar el límite por dirección solo para el tráfico anónimo.

2. Diez direcciones. Los pools de proxies residenciales las venden por miles a un precio muy bajo. Los límites por dirección hacen que el abuso cueste algo; no lo hacen difícil. Esta es la misma razón por la que limitar por IP apenas afecta un ataque distribuido.

3. Completamente dentro del límite. Nada dice cómo deben repartirse las mil solicitudes, así que todas pueden llegar de una sola vez y el endpoint recibe un pico del que nunca estuvo protegido. Eso es lo que controla la duración de la ventana, y elegir una hora permite un pico que una ventana de un minuto jamás dejaría pasar.

Tres preguntas, tres debilidades distintas, y solo la tercera tiene que ver con el algoritmo. Las primeras dos tienen que ver con qué cuentas y cuán barato es reemplazarlo.

Hacia dónde va esto

Un límite necesita tres decisiones: cuántas solicitudes, en qué ventana, contadas contra quién. El algoritmo es la forma en que las llevas.

Los contadores de ventana fija son el más simple de esos algoritmos, y el pico que dejan pasar es justo lo que existe para arreglar cada algoritmo posterior.