Para: operadores de sitios cuya búsqueda u otra función similar llama a una API externa. Este artículo generaliza algo que realmente ocurrió en un sitio que opera el operador de este sitio. No nombra ningún sitio ni ningún servicio externo, y no da límites exactos ni fechas. No cubre procedimientos de ataque.
Qué ocurrió
En un sitio que opera el operador de este sitio, la función de búsqueda llamaba a una API externa en cada búsqueda. En pocos días, el tráfico de búsqueda subió a unas 20 veces lo normal. La API externa tenía un límite de concurrencia, y la gran mayoría de las búsquedas (más del 90%) devolvían 503.
La primera suposición fue que un límite por IP (N por minuto) lo contendría. Eso era erróneo.
El tráfico de búsqueda subió unas 20 veces en pocos días
Se alcanzó el límite de concurrencia de la API externa y casi todas las búsquedas devolvieron 503. En ese momento solo parecía un aumento de errores.
Primera suposición: un límite por IP lo contendrá (errónea)
Contar por minuto y por IP detectaría a unas pocas IP que hacen un número muy alto de llamadas. Este no era ese tipo de tráfico.
Lo que mostró la medición
Las unas 60.000 búsquedas de un día procedieron de unas 60.000 IP distintas, aproximadamente una solicitud por IP. El patrón parecía una red de proxies residenciales. El user agent era un navegador común, el Referer era el propio sitio y las consultas eran nombres reales de productos. La recopilación de precios era el propósito probable.
La cuota diaria de la API externa se agotó temprano en el día
Las búsquedas del bot agotaron la cuota temprano y los visitantes normales no pudieron buscar durante gran parte del día.
Por qué no parecía el problema real
La cuota estaba protegida, por lo que la API externa parecía sana y el sitio solo veía más errores. Proteger la cuota y permitir que los usuarios usen la función resultaron ser cosas distintas.
Lo esperado: unas pocas IP haciendo muchas llamadas
Alcanza el límite por IP → detenido ✓
Lo ocurrido: unas 60.000 IP, una solicitud cada una
Ninguna IP alcanza el límite → solo se agota la cuota de la API externa
= mientras la unidad de conteo sea la IP, esta forma es invisible
Una cuota upstream protegida no significa que los usuarios puedan usar la función
Cualquier protección de la cuota o la concurrencia de una API externa existe para evitar que esa API se rompa. Mientras funciona, el upstream no muestra errores. El coste recae en el lado que perdió la cuota: sus propios visitantes.
Que la protección funcionara es lo que hizo difícil ver el problema. Lo que hay que vigilar es la tasa de éxito que obtienen los visitantes reales al buscar.
Cómo se detuvo
El diseño que no lo detuvo
Cualquier solicitud de búsqueda de cualquiera llama a la API externa. El único límite es un recuento por IP. El tráfico distribuido mantiene bajo el recuento de cada IP, por lo que nunca activa el límite.
El diseño que sí lo hizo
La API externa solo se llama para búsquedas que llevan un token firmado (cookie) emitido por la propia página del sitio. Sin token, se devuelve una página ligera o un 403. Además, se fijan límites horarios globales y por token.
- Token firmado
- Un token emitido por la propia página del sitio pasó a ser la condición para llamar a la API externa. Sin él, una página ligera o un 403
- Protección de agregados
- Las búsquedas sin token se excluyeron del ranking de búsquedas populares, que las consultas del bot habían inflado
- Límites horarios
- Tanto un límite global como un límite por token
Justo después de la publicación, los 503 bajaron a cero. Unas 100.000 solicitudes diarias sin token reciben ahora un 403, y las búsquedas normales funcionan.
Lecciones
- Un límite por IP no funciona contra un bot distribuido. Una solicitud por IP no detiene nada, por bajo que sea el límite.
- Una cuota upstream protegida no es lo mismo que los usuarios puedan usar la función. La protección puede ocultar el problema.
- Los agregados, como los rankings, se contaminan. Junto con proteger la API externa, restrinja lo que los alimenta.
Qué hacer en su lado
El siguiente orden es consejo propio de este sitio, no una afirmación de las fuentes citadas.
Verifique un token emitido por el sitio antes de cualquier paso costoso
Antes de un paso que consuma coste o cuota, como una llamada a una API externa, verifique un token firmado emitido por su propia página. Asigne al token una caducidad y verifíquelo en el servidor. Si falta, no continúe; devuelva una página ligera o un 403.
Mantenga el tráfico sin token fuera de los agregados
Construya las búsquedas populares, las estadísticas de consultas y las recomendaciones solo a partir de búsquedas con token, para que las consultas de un bot no se filtren a lo que muestra su sitio.
Fije límites globales y por token
Use un límite global horario y un límite por token en lugar de un recuento por IP. El límite global es el último respaldo que evita que se agote la cuota de la API externa.
Añada caché de resultados y colas
Sirva las consultas repetidas desde una caché sin volver a llamar a la API externa, y ponga las solicitudes en cola cuando haya mucha carga. Cuando una medida se evita, es menos probable que la cuota desaparezca de golpe.
Vigile la tasa de éxito que ven los visitantes
Registre la proporción de visitantes reales cuyas búsquedas tienen éxito, no solo la tasa de error de la API externa, y configure una alerta cuando baje. Este es el estado de "poder notar que algo va mal" de la base de seguridad organizacional.
Un token no es autenticación; eleva el coste para el atacante
Un token no es autenticación. Lo que un token aporta es frenar el tráfico que simplemente golpea la URL de búsqueda; no es una defensa completa.
Por eso se combina con caché, colas y límites por token. Según el criterio de este sitio, los límites por token no ayudan si un bot obtiene un token nuevo en cada ocasión, así que siempre combínelos con un límite global y con caché. El criterio de este sitio, como en limitación de tasa y control de abusos, es hacer que el abuso no merezca el coste, en lugar de llevar su tasa de éxito a cero.
Fuentes (primarias)
- OWASP API Security Top 10 2023, "API4:2023 Unrestricted Resource Consumption" — api-security.owasp.org (limitar la frecuencia con la que un cliente puede interactuar con la API en un periodo; configurar límites de gasto para servicios externos)
- OWASP Automated Threats, "OAT-011 Scraping" — owasp.github.io (define el scraping como la recopilación de contenido o datos para usarlos en otro lugar, como en la fijación de precios; los datos que no requieren autenticación pueden ser objetivo)
Lectura siguiente
- Diseño: Limitación de tasa y control de abusos: diseñar límites que frenen la fuerza bruta y los costes descontrolados
- Requisito previo: Suplantación de X-Forwarded-For y proxies de confianza (la base para contar por IP)
- Operaciones: La base de seguridad organizacional (cómo notar que algo va mal)