feat: Implement comprehensive security enhancements and deployment guide for AmayoWeb
- Added a detailed deployment guide (DEPLOYMENT_GUIDE.md) for frontend and backend setup. - Created an index documentation (INDEX.md) summarizing changes and available resources. - Established Nginx security configuration (NGINX_SECURITY_CONFIG.md) to protect backend IP and enforce rate limiting. - Developed a backend security guide (SECURITY_BACKEND_GUIDE.md) outlining security measures and best practices. - Introduced middleware for security, including rate limiting, CORS, and Cloudflare validation. - Updated frontend components and services to improve security and user experience. - Implemented logging and monitoring strategies for better security oversight.
This commit is contained in:
461
README/SECURITY_BACKEND_GUIDE.md
Normal file
461
README/SECURITY_BACKEND_GUIDE.md
Normal file
@@ -0,0 +1,461 @@
|
||||
# Guía de Seguridad Backend para Amayo
|
||||
|
||||
Esta guía contiene las mejoras de seguridad implementadas en el frontend y las recomendaciones para el backend para proteger la IP del servidor.
|
||||
|
||||
## 🛡️ Problema Identificado
|
||||
|
||||
Según el video de referencia (https://youtu.be/iXOlQszplC8), incluso con Cloudflare, un atacante puede:
|
||||
1. Ver el código fuente del frontend y encontrar URLs del backend
|
||||
2. Realizar timing attacks para encontrar la IP real del servidor
|
||||
3. Bypassear Cloudflare usando técnicas de header manipulation
|
||||
|
||||
## ✅ Soluciones Implementadas en el Frontend
|
||||
|
||||
### 1. Servicio de Seguridad (`src/services/security.js`)
|
||||
|
||||
#### Características:
|
||||
- **No expone URLs directamente en el código**: Las URLs se obtienen dinámicamente
|
||||
- **Token de sesión único**: Genera un token por sesión para identificar clientes
|
||||
- **Headers de seguridad**: Incluye timestamps y tokens en cada request
|
||||
- **Rate limiting client-side**: Previene abuso desde el cliente
|
||||
- **Validación de respuestas**: Verifica la autenticidad de las respuestas del servidor
|
||||
|
||||
### 2. Sistema de Rate Limiting
|
||||
|
||||
Implementado en `security.js`:
|
||||
```javascript
|
||||
- Login: 3 intentos por minuto
|
||||
- API calls: 30 requests por minuto
|
||||
- Default: 10 requests por minuto
|
||||
```
|
||||
|
||||
### 3. Protección CSRF
|
||||
|
||||
- State parameter en OAuth2
|
||||
- Validación de state en callbacks
|
||||
- Tokens de sesión únicos
|
||||
|
||||
### 4. Caché de Datos
|
||||
|
||||
- Stats del bot: 5 minutos
|
||||
- Info del bot: 1 hora
|
||||
- Reduce requests innecesarios
|
||||
|
||||
## 🔧 Recomendaciones para el Backend
|
||||
|
||||
### 1. Configuración de Cloudflare
|
||||
|
||||
#### A. Activar IP Anonymization
|
||||
```
|
||||
Cloudflare Dashboard > Security > Settings > Privacy > Enable IP Geolocation
|
||||
```
|
||||
|
||||
#### B. Bot Fight Mode
|
||||
```
|
||||
Cloudflare Dashboard > Security > Bots > Enable Bot Fight Mode
|
||||
```
|
||||
|
||||
#### C. Under Attack Mode (opcional)
|
||||
Para protección extra cuando se detecte un ataque:
|
||||
```
|
||||
Cloudflare Dashboard > Security > Settings > Security Level > I'm Under Attack
|
||||
```
|
||||
|
||||
#### D. Reglas de Firewall Personalizadas
|
||||
|
||||
```
|
||||
# Bloquear acceso directo a la IP
|
||||
- Si el request no viene de Cloudflare (validar CF-Connecting-IP)
|
||||
- Bloquear requests sin User-Agent
|
||||
- Bloquear requests sin X-Requested-With
|
||||
|
||||
# Rate Limiting Avanzado
|
||||
- 30 requests/minuto por IP
|
||||
- 100 requests/minuto por usuario autenticado
|
||||
```
|
||||
|
||||
### 2. Configuración del Servidor Backend (Express.js ejemplo)
|
||||
|
||||
```javascript
|
||||
// middleware/security.js
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import helmet from 'helmet';
|
||||
|
||||
// Verificar que el request viene de Cloudflare
|
||||
export const cloudflareOnly = (req, res, next) => {
|
||||
const cfIp = req.headers['cf-connecting-ip'];
|
||||
|
||||
// Lista de IPs de Cloudflare (actualizar periódicamente)
|
||||
const cloudflareIPs = [
|
||||
// https://www.cloudflare.com/ips/
|
||||
'173.245.48.0/20',
|
||||
'103.21.244.0/22',
|
||||
// ... más IPs
|
||||
];
|
||||
|
||||
if (!cfIp || !isCloudflareIP(req.ip, cloudflareIPs)) {
|
||||
return res.status(403).json({ error: 'Direct access forbidden' });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
// Rate limiting por endpoint
|
||||
export const apiLimiter = rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minuto
|
||||
max: 30, // 30 requests
|
||||
message: 'Too many requests from this IP',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
skip: (req) => {
|
||||
// Skip para requests autenticados con rate limit más alto
|
||||
return req.user && req.user.premium;
|
||||
}
|
||||
});
|
||||
|
||||
export const authLimiter = rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
max: 3, // Solo 3 intentos de login por minuto
|
||||
skipSuccessfulRequests: true
|
||||
});
|
||||
|
||||
// Headers de seguridad
|
||||
export const securityHeaders = helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
styleSrc: ["'self'", "'unsafe-inline'"],
|
||||
scriptSrc: ["'self'"],
|
||||
imgSrc: ["'self'", "data:", "https:"],
|
||||
},
|
||||
},
|
||||
hsts: {
|
||||
maxAge: 31536000,
|
||||
includeSubDomains: true,
|
||||
preload: true
|
||||
},
|
||||
referrerPolicy: { policy: 'same-origin' },
|
||||
noSniff: true,
|
||||
xssFilter: true,
|
||||
frameguard: { action: 'deny' }
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Validación de Headers
|
||||
|
||||
```javascript
|
||||
// middleware/validateRequest.js
|
||||
export const validateSecurityHeaders = (req, res, next) => {
|
||||
const requiredHeaders = [
|
||||
'x-client-token',
|
||||
'x-requested-with',
|
||||
'x-timestamp'
|
||||
];
|
||||
|
||||
// Verificar headers obligatorios
|
||||
for (const header of requiredHeaders) {
|
||||
if (!req.headers[header]) {
|
||||
return res.status(400).json({
|
||||
error: 'Missing security headers'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Validar timestamp (prevenir replay attacks)
|
||||
const timestamp = parseInt(req.headers['x-timestamp']);
|
||||
const now = Date.now();
|
||||
const maxAge = 5 * 60 * 1000; // 5 minutos
|
||||
|
||||
if (Math.abs(now - timestamp) > maxAge) {
|
||||
return res.status(401).json({
|
||||
error: 'Request expired'
|
||||
});
|
||||
}
|
||||
|
||||
// Agregar server token a la respuesta
|
||||
res.setHeader('X-Server-Token', generateServerToken());
|
||||
|
||||
next();
|
||||
};
|
||||
```
|
||||
|
||||
### 4. CORS Configuración Estricta
|
||||
|
||||
```javascript
|
||||
import cors from 'cors';
|
||||
|
||||
const corsOptions = {
|
||||
origin: (origin, callback) => {
|
||||
const allowedOrigins = [
|
||||
'https://docs.amayo.dev',
|
||||
'https://amayo.dev'
|
||||
];
|
||||
|
||||
// Permitir requests sin origin (mobile apps, etc)
|
||||
if (!origin) return callback(null, true);
|
||||
|
||||
if (allowedOrigins.includes(origin)) {
|
||||
callback(null, true);
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'));
|
||||
}
|
||||
},
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
||||
allowedHeaders: [
|
||||
'Content-Type',
|
||||
'Authorization',
|
||||
'X-Client-Token',
|
||||
'X-Requested-With',
|
||||
'X-Timestamp'
|
||||
],
|
||||
exposedHeaders: ['X-Server-Token'],
|
||||
maxAge: 86400 // 24 horas
|
||||
};
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
```
|
||||
|
||||
### 5. Ocultar Información del Servidor
|
||||
|
||||
```javascript
|
||||
// Remover headers que revelan información
|
||||
app.disable('x-powered-by');
|
||||
|
||||
app.use((req, res, next) => {
|
||||
res.removeHeader('Server');
|
||||
res.removeHeader('X-Powered-By');
|
||||
next();
|
||||
});
|
||||
```
|
||||
|
||||
### 6. Sistema de API Keys para el Frontend
|
||||
|
||||
En lugar de exponer el endpoint directamente, usar API keys rotativas:
|
||||
|
||||
```javascript
|
||||
// Generar API key para el frontend (rotar cada 24 horas)
|
||||
const generateApiKey = () => {
|
||||
const date = new Date().toISOString().split('T')[0];
|
||||
const secret = process.env.API_KEY_SECRET;
|
||||
return crypto
|
||||
.createHash('sha256')
|
||||
.update(date + secret)
|
||||
.digest('hex');
|
||||
};
|
||||
|
||||
// Middleware para validar API key
|
||||
export const validateApiKey = (req, res, next) => {
|
||||
const apiKey = req.headers['x-api-key'];
|
||||
const validKey = generateApiKey();
|
||||
|
||||
if (apiKey !== validKey) {
|
||||
return res.status(401).json({ error: 'Invalid API key' });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
```
|
||||
|
||||
### 7. Logging y Monitoreo
|
||||
|
||||
```javascript
|
||||
import winston from 'winston';
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.json(),
|
||||
transports: [
|
||||
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
||||
new winston.transports.File({ filename: 'security.log' })
|
||||
]
|
||||
});
|
||||
|
||||
// Log de requests sospechosos
|
||||
export const securityLogger = (req, res, next) => {
|
||||
const suspicious =
|
||||
!req.headers['cf-connecting-ip'] ||
|
||||
!req.headers['user-agent'] ||
|
||||
req.headers['user-agent'].includes('curl') ||
|
||||
req.headers['user-agent'].includes('wget');
|
||||
|
||||
if (suspicious) {
|
||||
logger.warn({
|
||||
type: 'suspicious_request',
|
||||
ip: req.ip,
|
||||
headers: req.headers,
|
||||
path: req.path,
|
||||
timestamp: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
```
|
||||
|
||||
### 8. Implementación en el Servidor
|
||||
|
||||
```javascript
|
||||
// server.js
|
||||
import express from 'express';
|
||||
import {
|
||||
cloudflareOnly,
|
||||
apiLimiter,
|
||||
authLimiter,
|
||||
securityHeaders,
|
||||
validateSecurityHeaders,
|
||||
securityLogger
|
||||
} from './middleware/security.js';
|
||||
|
||||
const app = express();
|
||||
|
||||
// Aplicar middlewares de seguridad
|
||||
app.use(securityHeaders);
|
||||
app.use(cloudflareOnly); // IMPORTANTE: Solo aceptar requests de Cloudflare
|
||||
app.use(securityLogger);
|
||||
app.use(validateSecurityHeaders);
|
||||
|
||||
// Rate limiting
|
||||
app.use('/api/', apiLimiter);
|
||||
app.use('/api/auth/', authLimiter);
|
||||
|
||||
// Ocultar endpoint real
|
||||
app.use('/api', (req, res, next) => {
|
||||
// No revelar estructura interna en errores
|
||||
res.locals.showStack = false;
|
||||
next();
|
||||
});
|
||||
|
||||
// Routes
|
||||
app.use('/api/auth', authRoutes);
|
||||
app.use('/api/bot', botRoutes);
|
||||
|
||||
// Error handler - no revelar información
|
||||
app.use((err, req, res, next) => {
|
||||
logger.error({
|
||||
error: err.message,
|
||||
stack: err.stack,
|
||||
ip: req.ip,
|
||||
path: req.path
|
||||
});
|
||||
|
||||
res.status(500).json({
|
||||
error: 'Internal server error',
|
||||
// No incluir detalles en producción
|
||||
...(process.env.NODE_ENV === 'development' && {
|
||||
message: err.message
|
||||
})
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## 🔒 Configuración de Variables de Entorno
|
||||
|
||||
### Frontend (.env)
|
||||
```env
|
||||
VITE_DISCORD_CLIENT_ID=your_client_id
|
||||
VITE_APP_VERSION=1.0.0
|
||||
# NO incluir URLs del backend aquí
|
||||
```
|
||||
|
||||
### Backend (.env)
|
||||
```env
|
||||
PORT=3000
|
||||
NODE_ENV=production
|
||||
API_KEY_SECRET=your_random_secret_here
|
||||
JWT_SECRET=your_jwt_secret_here
|
||||
DISCORD_CLIENT_SECRET=your_client_secret
|
||||
ALLOWED_ORIGINS=https://docs.amayo.dev,https://amayo.dev
|
||||
|
||||
# Database
|
||||
DATABASE_URL=your_database_url
|
||||
|
||||
# Cloudflare
|
||||
CLOUDFLARE_API_TOKEN=your_token
|
||||
```
|
||||
|
||||
## 📋 Checklist de Seguridad
|
||||
|
||||
### Frontend ✅
|
||||
- [x] Servicio de seguridad implementado
|
||||
- [x] Rate limiting client-side
|
||||
- [x] No URLs hardcodeadas
|
||||
- [x] Protección CSRF
|
||||
- [x] Validación de respuestas
|
||||
- [x] Sistema de caché
|
||||
|
||||
### Backend (Por Implementar)
|
||||
- [ ] Verificar requests de Cloudflare
|
||||
- [ ] Rate limiting server-side
|
||||
- [ ] Validación de headers de seguridad
|
||||
- [ ] CORS estricto
|
||||
- [ ] Ocultar información del servidor
|
||||
- [ ] Sistema de API keys
|
||||
- [ ] Logging y monitoreo
|
||||
- [ ] Error handling seguro
|
||||
|
||||
### Cloudflare
|
||||
- [ ] Bot Fight Mode activado
|
||||
- [ ] Reglas de firewall configuradas
|
||||
- [ ] Rate limiting configurado
|
||||
- [ ] SSL/TLS en modo Full (strict)
|
||||
- [ ] DNSSEC activado
|
||||
- [ ] Page Rules configuradas
|
||||
|
||||
## 🚀 Despliegue
|
||||
|
||||
### 1. Actualizar Cloudflare
|
||||
```bash
|
||||
# Configurar reglas de firewall
|
||||
# Dashboard > Security > WAF > Create firewall rule
|
||||
```
|
||||
|
||||
### 2. Actualizar el Backend
|
||||
```bash
|
||||
npm install helmet express-rate-limit cors winston
|
||||
```
|
||||
|
||||
### 3. Variables de Entorno
|
||||
Asegúrate de configurar todas las variables de entorno en producción.
|
||||
|
||||
### 4. Monitoreo
|
||||
Implementa un sistema de alertas para:
|
||||
- Intentos de acceso directo a la IP
|
||||
- Rate limiting excedido
|
||||
- Errores de seguridad
|
||||
- Requests sospechosos
|
||||
|
||||
## 📚 Recursos Adicionales
|
||||
|
||||
- [Cloudflare Security Best Practices](https://developers.cloudflare.com/fundamentals/security/)
|
||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||
- [Express Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html)
|
||||
- [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
|
||||
|
||||
## ⚠️ Notas Importantes
|
||||
|
||||
1. **Nunca expongas URLs del backend en el código del cliente**
|
||||
2. **Siempre valida que los requests vengan de Cloudflare**
|
||||
3. **Usa rate limiting tanto en cliente como en servidor**
|
||||
4. **Monitorea logs constantemente**
|
||||
5. **Mantén Cloudflare actualizado con las últimas reglas de seguridad**
|
||||
6. **Rota API keys regularmente**
|
||||
7. **Implementa un sistema de alertas**
|
||||
|
||||
## 🔄 Mantenimiento
|
||||
|
||||
### Semanal
|
||||
- Revisar logs de seguridad
|
||||
- Verificar rate limiting efectivo
|
||||
- Actualizar reglas de firewall si es necesario
|
||||
|
||||
### Mensual
|
||||
- Rotar API keys
|
||||
- Actualizar lista de IPs de Cloudflare
|
||||
- Revisar políticas de CORS
|
||||
- Auditar accesos sospechosos
|
||||
|
||||
### Trimestral
|
||||
- Realizar penetration testing
|
||||
- Actualizar dependencias de seguridad
|
||||
- Revisar y actualizar esta guía
|
||||
Reference in New Issue
Block a user