Denegación de servicio del modelo
Descripción
Los atacantes explotan operaciones del LLM que consumen muchos recursos para provocar costos excesivos, degradación del rendimiento o interrupciones del servicio. Los ataques apuntan al cómputo, la memoria o los límites de tasa de la API.
Riesgo
La inferencia del LLM es computacionalmente costosa y puede explotarse para el agotamiento de recursos. Los atacantes pueden enviar entradas diseñadas que maximizan el tiempo de procesamiento, el uso de memoria o la generación de tokens para degradar la disponibilidad del servicio o inflar los costos. Esto afecta a los usuarios legítimos mediante respuestas lentas, tiempos de espera agotados o la indisponibilidad total del servicio.
Escenarios de ataque
Un atacante satura una API de LLM con prompts de longitud máxima que solicitan salidas extremadamente largas, consumiendo recursos de GPU y bloqueando las solicitudes de otros usuarios.
Un actor malicioso descubre patrones de entrada que provocan el peor rendimiento del modelo, enviando solicitudes automatizadas que causan tiempos de procesamiento 10 veces más largos y agotan el presupuesto de cómputo.
Mitigaciones
Limitación de tasa
Implementar límites de tasa por usuario y por IP para las llamadas a la API del LLM. Utilizar algoritmos de token bucket o ventana deslizante para prevenir abusos por ráfagas.
Cuotas de recursos
Establecer límites máximos de tokens para las entradas y salidas. Aplicar tiempos de espera en las operaciones de inferencia para evitar procesamiento descontrolado.
Validación de solicitudes
Validar la complejidad de las solicitudes antes de procesarlas. Rechazar patrones evidentemente maliciosos, como repetición excesiva o estructuras anidadas.
Balanceo de carga
Distribuir las solicitudes entre varias instancias del modelo. Implementar colas y circuit breakers para manejar con elegancia las condiciones de sobrecarga.
Ejemplos de código
# Correcto: Validación de solicitudes y límites de recursos
from functools import wraps
import time
from collections import defaultdict
class LimitadorTasaLLM:
def __init__(self, solicitudes_maximas=100, ventana=60):
self.solicitudes_maximas = solicitudes_maximas
self.ventana = ventana
self.solicitudes = defaultdict(list)
def verificar_limite(self, id_usuario: str) -> bool:
ahora = time.time()
# Limpiar solicitudes antiguas
self.solicitudes[id_usuario] = [
t for t in self.solicitudes[id_usuario]
if ahora - t < self.ventana
]
# Verificar límite
if len(self.solicitudes[id_usuario]) >= self.solicitudes_maximas:
return False
self.solicitudes[id_usuario].append(ahora)
return True
def validar_solicitud(prompt: str, tokens_maximos: int = 4000):
if len(prompt) > tokens_maximos:
raise ValueError("El prompt excede el límite de tokens")
if prompt.count(prompt[:10]) > 5: # Detectar repetición
raise ValueError("Repetición excesiva detectada")
return True
Requisitos de evidencia
- Configuración de limitación de tasa y registros de aplicación
- Políticas de cuotas de recursos y paneles de monitoreo
- Resultados de pruebas de carga que demuestren resistencia a DoS
- Registros de respuesta a incidentes por intentos de agotamiento de recursos
- Métricas de uso de la API que muestren los límites por usuario