resetea.net/api/app.js
hacklab f2ff04ecdc fix(security): timeout de conexión en servidor HTTP — VULN: Slowloris DoS
Vulnerabilidad corregida:
- Slowloris: un atacante podía abrir cientos de conexiones TCP enviando
  headers/body a goteo (1 byte cada varios segundos) manteniendo el
  event loop de Node.js ocupado con sockets colgados indefinidamente,
  lo que bloquea peticiones legítimas (DoS por agotamiento de sockets).

Mitigación aplicada en el servidor HTTP:
  headersTimeout = 10s  — aborta si los headers no llegan en 10 s
  requestTimeout = 15s  — aborta si el body no llega en 15 s
  keepAliveTimeout = 5s — cierra keep-alive inactivos tras 5 s

Adicionalmente: warning al arrancar si SALT no está configurado en .env.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 17:26:25 +02:00

66 lines
2.6 KiB
JavaScript

'use strict';
require('dotenv').config();
const express = require('express');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const eraseRoute = require('./routes/erase');
const gmailOAuth = require('./routes/gmail_oauth');
const egosearch = require('./routes/egosearch');
const app = express();
app.set('trust proxy', 1); // confía en nginx para obtener la IP real del cliente
app.disable('x-powered-by');
app.use(helmet());
app.use(express.json({ limit: '10kb' }));
// Rate limiting general
app.use(rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
}));
// Rate limiting específico para envío de emails (más estricto)
const emailLimit = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hora
max: 10,
message: { error: 'Demasiadas solicitudes de envío. Espera antes de reintentar.' }
});
// ── Rate limits específicos ───────────────────────────────────────
const searchLimit = rateLimit({
windowMs: 60 * 1000, // 1 minuto
max: 8,
message: { error: 'Demasiadas búsquedas. Espera un momento.' }
});
// ── Rutas ────────────────────────────────────────────────────────
app.post('/api/erase', emailLimit, eraseRoute);
app.get('/api/egosearch', searchLimit, egosearch);
app.get('/api/gmail/auth', emailLimit, gmailOAuth.authInit);
app.get('/api/gmail/callback', gmailOAuth.authCallback);
// Health check
app.get('/api/health', (req, res) => res.json({ status: 'ok' }));
// ── Arranque ─────────────────────────────────────────────────────
const PORT = process.env.PORT || 8787;
const server = app.listen(PORT, '127.0.0.1', () => {
console.log(`RESETEA backend corriendo en 127.0.0.1:${PORT}`);
if (!process.env.GOOGLE_CLIENT_ID) {
console.warn('⚠ GOOGLE_CLIENT_ID no configurado — OAuth Gmail deshabilitado');
}
if (!process.env.SALT) {
console.warn('⚠ SALT no configurado en .env — el hash de referencia usa salt por defecto');
}
});
// Mitigación Slowloris: timeout en headers y body incompletos
server.headersTimeout = 10_000; // 10 s para recibir los headers completos
server.requestTimeout = 15_000; // 15 s para recibir el body completo
server.keepAliveTimeout = 5_000; // cierra keep-alive inactivos tras 5 s