Node.js y ExpressTesting y ProducciónLección 18 de 20
Seguridad en APIs
La seguridad en APIs REST tiene múltiples capas. helmet agrega headers HTTP de seguridad. express-rate-limit protege contra ataques de fuerza bruta. CORS configurado correctamente previene requests no autorizados. La sanitización previene inyección. Nunca expongas stack traces en producción.
// npm install helmet express-rate-limit
const express = require('express');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const cors = require('cors');
const app = express();
// 1. HELMET — agrega headers de seguridad HTTP automáticamente
// X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security, etc.
app.use(helmet());
// 2. CORS — configurado correctamente (no usar origin: "*" en producción)
const corsOptions = {
origin: (origin, callback) => {
const permitidos = [
'https://miapp.com',
'https://www.miapp.com',
'http://localhost:3000', // solo desarrollo
];
if (!origin || permitidos.includes(origin)) {
callback(null, true);
} else {
callback(new Error(`CORS: origen ${origin} no permitido`));
}
},
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
};
app.use(cors(corsOptions));
// 3. RATE LIMITING — limitar peticiones por IP
const limiterGeneral = rateLimit({
windowMs: 15 * 60 * 1000, // ventana de 15 minutos
max: 100, // máximo 100 requests por IP por ventana
standardHeaders: true,
legacyHeaders: false,
message: { error: 'Demasiadas peticiones. Intenta en 15 minutos.' },
});
// Rate limit más estricto para auth
const limiterAuth = rateLimit({
windowMs: 15 * 60 * 1000,
max: 10, // solo 10 intentos de login por 15min
message: { error: 'Demasiados intentos. Cuenta bloqueada 15 minutos.' },
});
app.use(limiterGeneral);
app.use('/api/v1/auth/login', limiterAuth);
// 4. SANITIZACIÓN — nunca confiar en el input
app.use(express.json({ limit: '10kb' })); // limitar tamaño del body
// 5. MANEJO DE ERRORES — no exponer detalles en producción
app.use((err, req, res, next) => {
const isProd = process.env.NODE_ENV === 'production';
res.status(err.status || 500).json({
error: isProd ? 'Error interno' : err.message,
// stack NUNCA en producción:
...(isProd ? {} : { stack: err.stack })
});
});
ConsejoLos 5 headers más importantes que agrega helmet: Content-Security-Policy (previene XSS), X-Frame-Options (previene clickjacking), Strict-Transport-Security (fuerza HTTPS), X-Content-Type-Options (previene MIME sniffing), Referrer-Policy.
Practica esta lección
Resuelve los ejercicios del curso de Node.js y Express en la app, gratis y con corrección automática.
Empezar a practicar