Saltar al contenido

Temas

OWASP API Security Top 10

Las categorías del API Security Top 10 de 2023, por qué las APIs fallan distinto a la web clásica (BOLA, mass assignment) y cómo defenderlas en la API de Citas.

IntermedioEn progreso 6 min de lectura1 oct 2026#owasp#api#bola#autorizacion#top-10

Casi todo el tráfico moderno es de APIs: una SPA o una app móvil no renderizan HTML en el servidor, hablan con una API JSON. Y las APIs fallan distinto a la web clásica, hasta el punto de que el OWASPOWASPFundación sin ánimo de lucro que publica recursos abiertos de seguridad de aplicaciones, como el Top 10 web y el Top 10 de APIs. les dedica su propia lista: el API Security Top 10. Su mensaje central es incómodo: los bugs más graves de las APIs no son inyecciones exóticas, sino fallos de autorización tan simples como cambiar un número en una petición.

Una lista aparte, y por qué#

El Top 10 web sigue aplicando a las APIs, pero se queda corto. En una web tradicional, el servidor controla qué pantallas ve el usuario; en una API, el cliente pide objetos por su identificador (/citas/124) y envía estructuras de datos (JSON) que el servidor deserializa. Eso abre dos clases de fallo que apenas existían antes:

  • Autorización por objeto: el servidor autentica quién eres, pero olvida comprobar si el objeto que pides es tuyo.
  • Mass assignment: el servidor vuelca el JSON recibido sobre su modelo y acepta campos que el usuario no debería poder tocar.

La edición vigente es la de 2023, con identificadores API1:2023 … API10:2023.

BOLA: cambiar un id para leer la cita de otro
Paciente Atoken sub=AAPI sin checkAPI con checkBD · citasGET /citas/123sesión ✓ · dueño ✗PII de B (cita 124)owner(124)=B ≠ sub=A403 Forbiddencita 123 → Acita 124 → Bsolo autenticaautentica y autoriza/citas/124SELECT 124cita de Bcita de B/citas/124403

Paso 1 de 5Dos pacientes

La base de datos guarda la cita 123 del paciente A y la cita 124 del paciente B. A está autenticado con su propio token (sub = A).

Las diez categorías (2023)#

# Categoría En una frase
API1 Broken Object Level Authorization (BOLA) No se comprueba que el objeto pedido pertenezca a quien lo pide. El riesgo nº 1.
API2 Broken Authentication Autenticación débil o mal implementada: tokens, sesiones, recuperación de cuenta.
API3 Broken Object Property Level Authorization (BOPLA) Se exponen o aceptan propiedades que el usuario no debería ver ni modificar (mass assignment + exceso de datos).
API4 Unrestricted Resource Consumption Sin límites de peticiones, tamaño o coste: puerta al DoS y al gasto descontrolado.
API5 Broken Function Level Authorization (BFLA) Un usuario accede a funciones fuera de su rol (acciones de administrador).
API6 Unrestricted Access to Sensitive Business Flows Flujos de negocio sin protección anti-automatización (reservar, comprar) que un bot abusa.
API7 Server Side Request Forgery La API pide una URL que controla el atacante → SSRF.
API8 Security Misconfiguration Configuración por defecto, CORS laxo, cabeceras ausentes, errores verbosos.
API9 Improper Inventory Management APIs y versiones olvidadas (shadow y zombie APIs) sin parchear ni documentar.
API10 Unsafe Consumption of APIs Confiar sin validar en las APIs de terceros que tú consumes.

Por qué las APIs fallan distinto#

BOLA: cambiar un id (API1)#

Es el fallo estrella, y el explainer de arriba lo muestra: la API comprueba que tienes una sesión válida —estás autenticado— y se detiene ahí, sin verificar que el objeto 124 sea tuyo. Un paciente pide GET /citas/124, que es de otro, y la API se la devuelve. No hace falta ninguna herramienta: basta editar la URL. En aplicaciones clásicas esto se llamaba IDOR (Insecure Direct Object Reference); en APIs es tan común que tiene el puesto número uno.

El error de fondo es confundir dos preguntas:

Mass assignment: aceptar de más (API3 / BOPLA)#

El otro patrón típico de APIs. Si el servidor vuelca el JSON recibido directamente sobre su modelo, el usuario puede enviar campos que no debería controlar:

Vulnerable

Seguro

vulnerable.js
// Mass assignment: se vuelca el body entero sobre el registro
app.patch('/pacientes/:id', auth, async (req, res) => {
await db.pacientes.update(req.params.id, req.body);
// el cliente envía { "nota": "...", "rol": "admin" } y escala privilegios
res.sendStatus(200);
});
seguro.js
// Esquema estricto: solo se aceptan los campos permitidos
app.patch('/pacientes/:id', auth, async (req, res) => {
if (req.params.id !== req.user.sub) return res.sendStatus(403); // + BOLA
const { nota, telefono } = schema.parse(req.body); // valida y descarta el resto
await db.pacientes.update(req.params.id, { nota, telefono });
res.sendStatus(200);
});

La otra cara de BOPLA es el exceso de datos expuestos: una API que devuelve el objeto entero (con hash_password, dni, flags internos) y confía en que el frontend “no los muestre”. El servidor debe devolver solo lo que corresponde, no filtrarlo en el cliente.

Defensas#

  1. Autorización por objeto en cada endpoint. Para cada petición que reciba un id, comprueba en el servidor que el objeto pertenece —o es accesible— a la identidad del token. No lo dejes en un middleware genérico que solo valida el token: la comprobación de propiedad es por objeto y por acción. Es mínimo privilegio a nivel de API.

  2. Esquema estricto de entrada y salida. Define qué campos se aceptan (allow-list, no el body entero) y qué campos se devuelven. Valida contra un esquema (Zod, JSON Schema, DTOs). Esto mata el mass assignment y el exceso de datos a la vez.

  3. Autorización por función (contra BFLA). Los endpoints de administrador deben verificar el rol, no solo esconderse de la UI. “No aparece en el menú” no es un control.

  4. Rate limiting y cuotas (contra API4 y API6). Límites por usuario y por IP, tamaños máximos de payload, y protección anti-automatización en los flujos sensibles (reservar citas). En AWS, API Gateway, AWS WAF (reglas rate-based) y límites en la propia app.

  5. Inventario de APIs (contra API9). Mantén documentadas todas las versiones y entornos. Retira las APIs zombie: la v1 sin parches que nadie recuerda es un punto de entrada perfecto.

Tu turno

Caza BOLAs y mass assignment en tu API

Sobre una API tuya o de tu laboratorio:

  • Haz un inventario de endpoints que reciben un id de objeto. Para cada uno, ¿comprueba la propiedad en el servidor, o solo que el token es válido?
  • Coge uno y haz la prueba del Callout: pide un objeto ajeno cambiando el id. Documenta el resultado.
  • Revisa los endpoints de escritura (POST/PATCH): ¿aceptan el body entero o un esquema estricto? Intenta enviar un campo de más (rol, isAdmin, saldo) y mira si lo acepta.
  • Comprueba si hay rate limiting en el login y en el flujo de reserva. ¿Qué pasa si envías 1 000 peticiones?

Reto

Tu API usa UUIDs aleatorios en vez de ids numéricos. ¿Te protege de BOLA?

▸Mostrar solución

No, solo lo dificulta. Un UUID no se adivina por fuerza bruta, pero se filtra constantemente: en listados, logs, URLs compartidas, respuestas de otros endpoints. En cuanto el atacante conoce un id ajeno (y suele conocerlo), si no hay comprobación de propiedad, accede. Los identificadores impredecibles son defensa en profundidad, no la autorización.

Reto

¿Por qué el Top 10 de APIs necesita existir si ya está el Top 10 web?

▸Mostrar solución

Porque el modelo de ataque cambia. En la web clásica, el servidor controla la navegación y muchos controles van implícitos en qué pantallas sirve. Una API expone objetos por id y acepta estructuras de datos directamente del cliente, lo que hace que la autorización por objeto y por propiedad (BOLA, BOPLA, BFLA) sea el fallo dominante, por encima de la inyección. El Top 10 de APIs reordena las prioridades para ese mundo.

En resumen#

  • Las APIs fallan distinto: el riesgo dominante es la autorización, no la inyección.
  • BOLA (API1) es el nº 1: no comprobar que el objeto pedido es tuyo. BOPLA (API3, propiedad) y BFLA (API5, función) completan el trío.
  • Mass assignment y el exceso de datos vienen de volcar/devolver estructuras enteras sin esquema.
  • Defensas: autorización por objeto en cada endpoint, esquema estricto de entrada y salida, autorización por función, rate limiting e inventario de APIs.
  • Autenticar no es autorizar; los UUID ayudan pero no autorizan.

Referencias#

Notas relacionadas

ESC
↑↓ para navegar↵ para abriresc para cerrar