Explica los 10 riesgos de seguridad más críticos específicos de las API y cómo mitigarlos.
Una clasificación de los riesgos de seguridad específicos de las API publicada por OWASP (Open Worldwide Application Security Project). La edición 2023 ofrece la lista más reciente que refleja las amenazas que han aumentado con la adopción generalizada de las API.
Una vulnerabilidad que permite el acceso no autorizado a los datos de otros usuarios mediante la manipulación de los ID de los objetos. Se conoce como la vulnerabilidad más frecuente y más fácil de explotar.
Los atacantes pueden acceder a la información personal de otros usuarios, detalles de pago, historial de pedidos y mucho más simplemente cambiando el ID en la URL o los parámetros de solicitud.
// Recibe ID y devuelve datos directamente - sin comprobación de autorización app.get('/api/users/:id/orders', async (req, res) => { const orders = await Order.find({ userId: req.params.id }); res.json(orders); });
// Verificar con el ID del usuario autenticado para comprobar la autorización app.get('/api/users/:id/orders', authenticate, async (req, res) => { if (req.user.id !== req.params.id && !req.user.isAdmin) { return res.status(403).json({ error: 'Forbidden' }); } const orders = await Order.find({ userId: req.params.id }); res.json(orders); });
Una vulnerabilidad que permite a los atacantes apoderarse de cuentas de usuario legítimas debido a implementaciones defectuosas del mecanismo de autenticación.
Políticas de contraseñas débiles, gestión inadecuada de tokens, falta de protección contra fuerza bruta, gestión inadecuada de sesiones, etc.
const jwt = require('jsonwebtoken'); function authenticate(req, res, next) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Token required' }); try { // Especifica explícitamente el algoritmo (evita el ataque alg: none) const decoded = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'], issuer: 'your-app', }); req.user = decoded; next(); } catch (err) { res.status(401).json({ error: 'Invalid token' }); } }
Una vulnerabilidad en la que el control de acceso sobre las propiedades (campos) de los objetos incluidos en las respuestas de la API es insuficiente. Este elemento combina la Exposición Excesiva de Datos y la Asignación Masiva.
// Devolver sólo los campos públicos del objeto usuario function sanitizeUser(user, requesterId) { const publicFields = { id: user.id, name: user.name, avatar: user.avatar }; // Sólo el propietario puede ver los campos adicionales if (requesterId === user.id) { publicFields.email = user.email; publicFields.phone = user.phone; } return publicFields; // ❌ return user; would leak password_hash etc. }
Una vulnerabilidad en la que no hay límites en el tamaño de las solicitudes de API, la frecuencia o el consumo de recursos, lo que provoca ataques DoS o aumentos de costes.
const rateLimit = require('express-rate-limit'); // Limitación global de la velocidad app.use(rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutos max: 100, // Máximo 100 solicitudes standardHeaders: true, })); // Límite de tamaño de la carga útil app.use(express.json({ limit: '10kb' })); // Límite superior de paginación app.get('/api/items', (req, res) => { const limit = Math.min(parseInt(req.query.limit) || 20, 100); // ... });
Una vulnerabilidad en la que no se implementa un control de acceso adecuado para las funciones de administración y los puntos finales, lo que permite a los usuarios normales realizar operaciones administrativas.
function authorize(...roles) { return (req, res, next) => { if (!roles.includes(req.user.role)) { return res.status(403).json({ error: 'Insufficient permissions' }); } next(); }; } // Acceso sólo para administradores app.delete('/api/admin/users/:id', authenticate, authorize('admin'), deleteUser); // Administrador y moderador app.put('/api/posts/:id/moderate', authenticate, authorize('admin', 'moderator'), moderatePost);
Una vulnerabilidad en la que los flujos lógicos críticos del negocio no están protegidos contra ataques automatizados. Ejemplos: reventa de entradas, recogida masiva de cupones, envío de spam, etc.
Una vulnerabilidad en la que el servidor obtiene una URL proporcionada por el usuario sin validación, lo que permite el acceso no autorizado a redes internas.
const { URL } = require('url'); function isAllowedUrl(input) { try { const url = new URL(input); // Restringir protocolos if (!['https:', 'http:'].includes(url.protocol)) return false; // Bloquear rangos de IP privadas const blocked = ['127.0.0.1', 'localhost', '0.0.0.0', '169.254.169.254']; if (blocked.includes(url.hostname)) return false; // Compruebe los rangos de red internos (10.x, 172.16-31.x, 192.168.x) if (/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(url.hostname)) return false; return true; } catch { return false; } }
Configuraciones de seguridad inadecuadas en servidores API o frameworks. Incluye permitir métodos HTTP innecesarios, políticas CORS demasiado permisivas, exposición de información de depuración, etc.
const helmet = require('helmet'); const cors = require('cors'); app.use(helmet()); app.use(cors({ origin: ['https://app.example.com'], // No utilizar comodines methods: ['GET', 'POST', 'PUT', 'DELETE'], credentials: true, })); // Gestor de errores: no devolver trazas de pila en producción app.use((err, req, res, next) => { res.status(500).json({ error: process.env.NODE_ENV === 'production' ? 'Internal Server Error' : err.message, }); });
Estado en el que se dejan expuestas versiones antiguas de puntos finales de API sin aplicar parches de seguridad. También se conoce como API en la sombra o API zombi.
Una vulnerabilidad en la que se confía en las respuestas de API de terceros sin validación. Si una API externa se ve comprometida, el impacto se propaga a su propio sistema.
const Ajv = require('ajv'); const ajv = new Ajv(); // Validar respuestas API externas con un esquema const externalSchema = { type: 'object', required: ['id', 'status'], properties: { id: { type: 'string', maxLength: 50 }, status: { type: 'string', enum: ['active', 'inactive'] }, }, additionalProperties: false, }; const validate = ajv.compile(externalSchema); async function fetchExternalData() { const res = await fetch('https://api.external.com/data'); const data = await res.json(); if (!validate(data)) { throw new Error('External API response validation failed'); } return data; }
| ID | Vulnerabilidad | Gravedad | Mitigación clave |
|---|---|---|---|
| API1 | Broken Object Level Authorization | Critical | Comprobaciones de autorización a nivel de objeto |
| API2 | Broken Authentication | Critical | Gestión adecuada de tokens y protección por fuerza bruta |
| API3 | Broken Object Property Level Authorization | High | Filtrado explícito del campo de respuesta |
| API4 | Unrestricted Resource Consumption | High | Limitación de velocidad y restricciones del tamaño de la carga útil |
| API5 | Broken Function Level Authorization | High | Control de acceso basado en funciones |
| API6 | Unrestricted Access to Sensitive Business Flows | Medium | CAPTCHA y limitación de tarifas a nivel empresarial |
| API7 | Server Side Request Forgery | High | Validación de URL y bloqueo de IP privadas |
| API8 | Security Misconfiguration | Medium | Cabeceras de seguridad y configuración CORS |
| API9 | Improper Inventory Management | Medium | Gestión del inventario de API y políticas de amortización |
| API10 | Unsafe Consumption of APIs | Medium | Validación de esquemas de respuestas de API externas |