# Límites de peticiones

> Limita cuántas peticiones acepta una ruta por IP, cabecera, cookie o campo JSON, por nombre o para toda la zona, con acciones de bloqueo, reto o registro.

OpenWAF tiene tres tipos de límite de peticiones. Se cuentan en el borde, antes de que las peticiones lleguen a tu origen.

| Tipo | Dónde | Cuenta | Para qué |
|---|---|---|---|
| [Reglas de límite de peticiones](#per-path-rules) (`rate_rules`) | Ajuste de borde, hasta 25 por lista | Por IP, cabecera, cookie o campo del cuerpo JSON, en cualquier periodo | Inicios de sesión, códigos de un solo uso, cambios de contraseña, API caras. **Recomendadas.** |
| [Reglas de límite por ruta](#rate-limit-rules) (`kind=rate_limit`) | Regla de borde | Por IP y por minuto | Límites sencillos por ruta. |
| [Límite básico](#basic-rate-limit) (`rate_limit_rpm`) | Ajuste de borde | Por IP y por minuto, todo el sitio | Un techo para todo. |

No hay ninguno por defecto.

## Reglas de límite de peticiones

Cada regla cuenta las peticiones que casan con una ruta (y, si quieres, con unos métodos, una cabecera o un parámetro de la query) **por clave**. Cuando una clave pasa de `requests` peticiones en `period` segundos, se le aplica la `action` de la regla, si quieres durante un `mitigation_timeout`.

```json
{"name": "Login", "path_prefix": "/auth/login", "methods": ["POST"], "key": "ip",
 "requests": 60, "period": 900, "algorithm": "gcra", "action": "block", "mitigation_timeout": 900}
```

### Cómo se evalúan

1. Las reglas de límite de peticiones se miran después de las reglas por IP, las listas de amenazas y las reglas por país, y antes de los demás límites; también para las IP permitidas y en cualquier modo del WAF. Nunca se aplican a las rutas `/__waf/`.
2. **Todas** las reglas que casan cuentan la petición, cada una en su contador y en el orden de la lista.
3. La **primera** regla que está por encima de su límite con la acción `block` o `challenge` responde. Las reglas `log` solo dejan un evento y la petición sigue.

### Claves

| `key` | Cuenta por | Notas |
|---|---|---|
| `ip` (por defecto) | IP del cliente | Las IPv6 se agrupan por /64. |
| `header` | Primer valor de la cabecera `key_name` | P. ej. `x-api-key`. |
| `cookie` | Valor de la cookie `key_name` | P. ej. una cookie de sesión. |
| `body_field` | Un campo del cuerpo JSON, `key_name` como `email` o `user.email` (hasta 4 niveles) | Se compara en minúsculas. Solo se lee si el `Content-Type` es `application/json` (o `application/*+json`) y el `Content-Length` declarado está entre 1 byte y 8 KiB; el cuerpo llega intacto al origen. |

Si la clave no tiene valor (falta la cabecera o la cookie, el cuerpo no es un JSON pequeño), la petición se cuenta **por IP**: quitar la cabecera nunca sirve para saltarse la regla. Los valores de la clave nunca salen del nodo en claro ni aparecen en los eventos.

### Algoritmos

- `sliding_window` (por defecto): hasta `requests` por `period`, contadas con una ventana deslizante.
- `gcra` (ritmo constante): una ráfaga de `requests` y luego una más cada `period / requests` segundos. Quien sigue intentándolo se frena de forma uniforme en vez de esperar a que acabe la ventana. Recomendado para el inicio de sesión.

### Acciones

| `action` | Respuesta |
|---|---|
| `block` (por defecto) | `429 Too Many Requests` con `Retry-After` (segundos). Los navegadores reciben la [página de bloqueo](https://developers.openwaf.dev/es/waf/block-page/) del sitio; el resto de clientes, `{"error":"rate_limited","retry_after":N}`. |
| `challenge` | Las navegaciones de navegador reciben el [reto de navegador](https://developers.openwaf.dev/es/waf/browser-challenge/) y, una vez resuelto, pasan sin contar mientras dure el pase. Todo lo demás (un `POST` de login, una llamada a la API) recibe el `429` de `block`. |
| `log` | Solo un evento; la petición sigue. Sirve para ajustar un límite antes de aplicarlo. |

Con `mitigation_timeout` mayor que 0, la petición que cruza el límite activa un castigo para esa clave: durante esos segundos, sus peticiones que casan reciben la acción directamente, sin contar. Con `0`, la acción solo se aplica mientras la clave está por encima del límite.

### Varios nodos de borde

Cada nodo de borde cuenta por su cuenta. Cuando varios nodos sirven tu sitio, un cliente podría repartir sus peticiones entre ellos. Con `per_node_divisor: true` (por defecto), cada nodo permite `ceil(requests / puntos de entrada)`, así que el límite vale para todos juntos. Un cliente legítimo que siempre llega al mismo nodo tiene entonces solo su parte.

Pon `per_node_divisor: false` cuando el límite del borde tenga que quedar **por encima** del límite por IP de tu propia aplicación, para que tu aplicación responda antes con su mensaje y el borde sea solo la red de seguridad.

> **Atención: IP compartidas**
>
> Todos los que están detrás de una misma wifi (una oficina, un gimnasio, un colegio) comparten IP pública. Mantén los límites por IP por encima de lo que tu aplicación ya permite por IP y añade una segunda regla con la clave `body_field` `email` si necesitas un límite por cuenta.


### Plantillas

El panel ofrece estos puntos de partida (**Empezar con una plantilla**):

```json
[{"name": "Enviar código", "path_prefix": "/auth/send-otp", "methods": ["POST"], "requests": 40, "period": 600,
  "action": "block", "mitigation_timeout": 600},
 {"name": "Verificar código", "path_prefix": "/auth/verify-otp", "methods": ["POST"], "requests": 60, "period": 600,
  "action": "block", "mitigation_timeout": 600}]
```

```json
{"name": "API general", "path_prefix": "/api", "requests": 600, "period": 60, "action": "log"}
```

### Añadir una regla

**Panel**

Dominio → **Seguridad → Límites de peticiones** → **Añadir regla**, o elige una plantilla en **Empezar con una plantilla**. Rellena **Peticiones que cuentan**, **Contar por**, **Límite**, **Cómo contar** y **Entonces**, aplica, ordena las reglas con las flechas y pulsa **Guardar cambios**. La columna **Últimas 24 h** enseña cuántas peticiones limitó cada regla.
**CLI**

```sh
openwaf-cloud ctl ratelimit add example.com id=login path_prefix=/auth/login methods=POST limit=60/15m \
  algorithm=gcra action=block timeout=15m per_node_divisor=false --reason "Límite del login"
openwaf-cloud ctl ratelimit list example.com
openwaf-cloud ctl ratelimit set example.com login requests=80 --reason "Más margen"
openwaf-cloud ctl ratelimit rm example.com login --reason "Ya no hace falta"
```
`limit=N/periodo` y `timeout=duración` son atajos de `requests`/`period` y de `mitigation_timeout`. Cada orden lee la lista, la cambia y la guarda con la comprobación de versión.
**API**

Las reglas forman parte de los ajustes de borde y un `PATCH` **sustituye la lista entera** (`[]` las quita todas). Lee antes la lista actual con `GET …/edge`.
```sh
curl -sS -X PATCH "https://dash.openwaf.dev/v1/orgs/$ORG/zones/example.com/edge" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Límite del login" \
  -H "Content-Type: application/json" \
  -d '{"rate_rules": [{"name": "Login", "hosts": ["api.example.com"], "path_prefix": "/auth/login",
       "methods": ["POST"], "requests": 60, "period": 900, "algorithm": "gcra", "action": "block",
       "mitigation_timeout": 900, "per_node_divisor": false}]}'
```
**MCP**

`update_settings` con `settings.rate_rules` (la lista entera). Simula, revisa las diferencias y confirma con `confirm=true` y `expected_version`.


Todos los campos están en la [referencia de reglas](https://developers.openwaf.dev/es/waf/rule-reference/#rate-limiting-rule-fields).

### Una lista por nombre

Un nombre puede tener su propia lista en `hosts.<nombre>.rate_rules`: **sustituye** a la de la zona para ese nombre (`[]` = ninguna regla; `null` = volver a la lista de la zona). Usa `--host www.example.com` con las órdenes `ratelimit`, o `host` con `update_settings`. El panel enseña estos nombres, pero todavía no edita sus listas. Consulta [Ajustes por nombre](https://developers.openwaf.dev/es/rules/per-name-settings/).

### Eventos

Cada acción deja un [evento de seguridad](https://developers.openwaf.dev/es/analytics/security-events/) con `rule_name` `rate_rule:<id>`, `attack_type` `rate_limit`, estado 429, 503 (reto) o 200 (registro) y un mensaje como `Rate rule login: over 60 per 900 s (key ip)`, nunca el valor de la clave.

## Reglas de límite por ruta

Una regla de borde de tipo `rate_limit` cuenta las peticiones por IP y por minuto natural en un `path_pattern` (vacío o `*` = cualquier ruta, acabado en `*` = prefijo, si no, exacta) y un `method` opcional. Un cliente puede hacer `rpm + burst` peticiones por minuto; las siguientes reciben `429` con la página de bloqueo. `rpm: 0` bloquea todas las peticiones que casan.

Si casan varias reglas, una con ruta concreta gana a otra que vale para todo.

**Panel**

Dominio → **Seguridad → Firewall → Reglas → Límites de peticiones** → **Añadir límite**.
**CLI**

```sh
openwaf-cloud ctl rules add example.com kind=rate_limit path_pattern='/api/*' method=POST rpm=120 burst=20 --reason "Escrituras de la API"
```
**API**

```sh
curl -sS -X POST "https://dash.openwaf.dev/v1/orgs/$ORG/zones/example.com/rules" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "X-Change-Reason: Escrituras de la API" \
  -H "Content-Type: application/json" \
  -d '{"kind": "rate_limit", "path_pattern": "/api/*", "method": "POST", "rpm": 120, "burst": 20}'
```
**MCP**

`add_rule` con `"kind": "rate_limit"`, `path_pattern`, `method`, `rpm` y `burst`.


## Límite básico

`rate_limit_rpm` limita las peticiones por minuto de una IP a un nombre (IPv6 por /64). `0` (por defecto) lo apaga. No se aplica mientras el WAF está apagado (`mode=off` o `waf_level=off`). La respuesta es `429` con la página de bloqueo.

```sh
openwaf-cloud ctl zones set example.com rate_limit_rpm=600 --reason "Techo para todo el sitio"
```

En el panel: **Seguridad → Firewall → Protección → Límite básico (peticiones por minuto y por IP)**.
