Cómo construir una API REST segura con Node.js y Express: guía práctica
Una API REST segura no consiste en añadir un token al encabezado y dar el trabajo por terminado. Hay que definir quién puede hacer cada operación, validar entradas, limitar abusos, registrar eventos sin filtrar secretos y responder con la menor cantidad de información posible. Esta guía reúne un diseño práctico para Node.js y Express.
- Empieza por el límite de confianza
- Autenticación no es autorización
- Valida el cuerpo, los parámetros y las consultas
- Protege credenciales y sesiones
- Limita velocidad y tamaño
- Errores, cabeceras y CORS
- Registra lo necesario para investigar
- Pruebas mínimas antes de publicar
- Checklist de despliegue
- Conclusión
- Fuentes oficiales
Empieza por el límite de confianza
Antes de escribir rutas, dibuja qué componentes se hablan entre sí: cliente, proxy, API, base de datos y servicios externos. Cada salto necesita autenticación, autorización y un canal cifrado cuando atraviesa una red no confiable. La API no debe aceptar como verdad ningún dato enviado por el navegador, aunque la interfaz lo haya validado.
Autenticación no es autorización
La autenticación identifica al usuario. La autorización decide si puede ejecutar una acción sobre un recurso concreto. Un usuario autenticado no debería poder consultar el pedido de otro solo porque conoce su identificador. Comprueba la pertenencia del recurso en el servidor:
app.get('/api/orders/:id', requireAuth, async (req, res, next) => {
try {
const order = await orders.findById(req.params.id);
if (!order || order.userId !== req.user.id) {
return res.status(404).json({ error: 'Pedido no encontrado' });
}
res.json({ id: order.id, status: order.status, total: order.total });
} catch (error) {
next(error);
}
});
Devolver 404 en este caso evita revelar si existe un recurso perteneciente a otra persona. La respuesta exacta depende del modelo de amenazas y de las necesidades de auditoría, pero debe ser una decisión consciente.
Valida el cuerpo, los parámetros y las consultas
Valida tipos, tamaños, formatos y valores permitidos en el servidor. Rechaza campos desconocidos cuando sea posible. Para acceder a la base de datos usa consultas parametrizadas o un ORM bien configurado; nunca construyas SQL concatenando texto que proviene de una petición.
const createOrder = {
body: {
productId: { type: 'string', minLength: 1, maxLength: 64 },
quantity: { type: 'integer', minimum: 1, maximum: 20 }
}
};
El ejemplo representa el contrato; en producción aplica un validador mantenido y devuelve errores consistentes. No incluyas en la respuesta trazas, consultas SQL, rutas del servidor ni mensajes internos.
Protege credenciales y sesiones
Las claves de servicios externos deben vivir en el gestor de secretos o en variables de entorno protegidas, nunca en el repositorio. Rota las credenciales y usa permisos mínimos. Si utilizas cookies para la sesión, configura Secure, HttpOnly y una política SameSite coherente con tu arquitectura. Si usas tokens, define expiración, revocación y protección ante robo.
No registres contraseñas, tokens completos, cookies, números de tarjeta ni documentos personales. En logs utiliza identificadores de correlación y valores truncados.
Limita velocidad y tamaño
Una API pública necesita límites por IP, usuario o clave, además de un tamaño máximo de cuerpo y tiempos de espera. El límite correcto debe medirse: uno muy bajo rompe clientes legítimos y uno muy alto no ayuda contra abuso. Responde con 429 Too Many Requests y una política clara de reintentos.
import rateLimit from 'express-rate-limit';
app.use('/api/auth', rateLimit({
windowMs: 15 * 60 * 1000,
limit: 20,
standardHeaders: 'draft-8',
legacyHeaders: false
}));
Coloca el límite de autenticación antes de las rutas sensibles y considera el proxy inverso al determinar la IP real. Configura trust proxy solo para proxies que controles.
Errores, cabeceras y CORS
Usa un manejador central de errores y un formato estable. En producción no envíes el stack trace al cliente. Añade cabeceras de seguridad con una configuración revisada y permite CORS únicamente para orígenes que realmente necesitan llamar a la API. Un comodín combinado con credenciales suele ser una mala configuración.
app.use((err, req, res, next) => {
req.log?.error({ err, requestId: req.id });
res.status(500).json({ error: 'Error interno', requestId: req.id });
});
Registra lo necesario para investigar
Registra fecha, ruta, método, código de respuesta, duración, identificador de solicitud y un identificador de usuario no sensible. Conserva los logs durante el tiempo necesario, limita su acceso y define quién puede exportarlos. Un registro útil permite responder qué ocurrió sin convertirse en otra fuga de datos.
Pruebas mínimas antes de publicar
- Una petición sin autenticación recibe 401 en las rutas protegidas.
- Un usuario no puede leer ni modificar recursos de otro.
- Los campos desconocidos y valores fuera de rango se rechazan.
- Las consultas usan parámetros y no concatenación.
- Se bloquean cuerpos demasiado grandes y demasiadas peticiones.
- Los errores no exponen secretos, rutas ni trazas.
- Los logs permiten correlacionar una petición sin guardar credenciales.
- Las dependencias se actualizan y se revisan en CI.
Checklist de despliegue
- HTTPS termina en un proxy configurado correctamente.
- La API se ejecuta con un usuario sin privilegios de sistema.
- La base de datos no está expuesta públicamente.
- Los secretos se inyectan desde un almacén protegido.
- Las métricas tienen alertas para errores, latencia y saturación.
- Existe un procedimiento para revocar tokens y rotar claves.
Conclusión
La seguridad de una API se sostiene en decisiones pequeñas y verificables: autorización por recurso, validación en el servidor, secretos fuera del código, límites medibles y logs útiles. Si documentas esas decisiones y las pruebas en cada despliegue, reduces errores repetidos y haces que el sistema sea más fácil de mantener.
Fuentes oficiales
- OWASP API Security Project.
- Buenas prácticas de seguridad de Express.
- Buenas prácticas de seguridad de Node.js.
Si quieres conocer otros artículos parecidos a Cómo construir una API REST segura con Node.js y Express: guía práctica puedes visitar la categoría Blog.
Deja una respuesta

También puede gustarte: