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.

Índice de Contenido 💻
  1. Empieza por el límite de confianza
  2. Autenticación no es autorización
  3. Valida el cuerpo, los parámetros y las consultas
  4. Protege credenciales y sesiones
  5. Limita velocidad y tamaño
  6. Errores, cabeceras y CORS
  7. Registra lo necesario para investigar
  8. Pruebas mínimas antes de publicar
  9. Checklist de despliegue
  10. Conclusión
  11. 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

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.

También puede gustarte:

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir