🎓 Initial commit: Math2 Platform - Plataforma de Álgebra Lineal PRO
✨ Características: - 45 ejercicios universitarios (Basic → Advanced) - Renderizado LaTeX profesional - IA generativa (Z.ai/DashScope) - Docker 9 servicios - Tests 123/123 pasando - Seguridad enterprise (JWT, XSS, Rate limiting) 🐳 Infraestructura: - Next.js 14 + Node.js 20 - PostgreSQL 15 + Redis 7 - Docker Compose completo - Nginx + SSL ready 📚 Documentación: - 5 informes técnicos completos - README profesional - Scripts de deployment automatizados Estado: Producción lista ✅
This commit is contained in:
170
backend/SECURITY_CHANGELOG.md
Normal file
170
backend/SECURITY_CHANGELOG.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# Documentación de Cambio de Seguridad - Token Blacklist
|
||||
|
||||
## Resumen
|
||||
Se corrigió un **FAIL-OPEN CRÍTICO** en la verificación de token blacklist que permitía el bypass de autenticación cuando Redis estaba indisponible.
|
||||
|
||||
## Fecha del Cambio
|
||||
2024-03-30
|
||||
|
||||
## Archivo Modificado
|
||||
`backend/src/shared/database/redis.client.ts`
|
||||
|
||||
## Problema Original (Líneas 145-157)
|
||||
|
||||
```typescript
|
||||
} catch (error) {
|
||||
logger.error({ error }, 'Redis unavailable - cannot check token blacklist');
|
||||
// Return false to allow request to proceed (fail-open for availability)
|
||||
// Note: This is a security trade-off. If strict security is required,
|
||||
// change to return true (fail-closed)
|
||||
return false; // <-- BYPASS DE SEGURIDAD CRÍTICO
|
||||
}
|
||||
```
|
||||
|
||||
**Riesgo**: Cuando Redis fallaba, cualquier token (incluso los blacklisteados) se consideraba válido, permitiendo autenticación no autorizada.
|
||||
|
||||
## Solución Implementada
|
||||
|
||||
### 1. Comportamiento FAIL-CLOSED (Seguridad Máxima)
|
||||
```typescript
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
error: (error as Error).message,
|
||||
consecutiveFailures,
|
||||
tokenPrefix: token.substring(0, 10),
|
||||
timestamp: new Date().toISOString(),
|
||||
service: 'token-blacklist',
|
||||
circuitBreakerOpen: false
|
||||
}, 'Redis unavailable - SECURITY: blocking token');
|
||||
|
||||
throw new AuthenticationError('Unable to verify token status. Service temporarily unavailable.');
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Circuit Breaker con Fallback
|
||||
- **Umbral**: 5 fallos consecutivos activan el circuit breaker
|
||||
- **Fallback**: Cache en memoria (TTL 1 minuto) para operaciones de blacklist
|
||||
- **Hashing**: SHA256 para almacenamiento seguro (nunca guarda tokens completos)
|
||||
|
||||
### 3. Retry con Backoff Exponencial
|
||||
- **Intentos**: 3 reintentos máximo
|
||||
- **Delay**: 100ms × intento (100ms, 200ms, 300ms)
|
||||
|
||||
### 4. Métricas de Monitoreo
|
||||
```typescript
|
||||
const metrics = {
|
||||
redisBlacklistFailures: 0, // Fallos totales
|
||||
redisBlacklistConsecutiveFailures: 0, // Fallos consecutivos actuales
|
||||
redisBlacklistSuccesses: 0, // Éxitos totales
|
||||
circuitBreakerOpens: 0 // Veces que se abrió el circuit breaker
|
||||
};
|
||||
```
|
||||
|
||||
### 5. Logging Estructurado
|
||||
- Nunca se loguean tokens completos (solo prefijo de 10 caracteres)
|
||||
- Timestamp ISO8601
|
||||
- Identificación de servicio
|
||||
- Contadores de fallos consecutivos
|
||||
|
||||
## Cambios de Comportamiento
|
||||
|
||||
| Escenario | Antes (FAIL-OPEN) | Después (FAIL-CLOSED) |
|
||||
|-----------|-------------------|----------------------|
|
||||
| Redis indisponible | Token permitido ❌ | Error 401 lanzado ✅ |
|
||||
| Error temporal | Token permitido ❌ | Retry con backoff ✅ |
|
||||
| 5+ fallos consecutivos | Token permitido ❌ | Circuit breaker activado ✅ |
|
||||
| Verificación exitosa | Token rechazado/aceptado | Sin cambios ✅ |
|
||||
|
||||
## Impacto en Disponibilidad
|
||||
|
||||
⚠️ **IMPORTANTE**: Este cambio puede causar downtime del servicio de autenticación si Redis falla.
|
||||
|
||||
### Recomendaciones para Alta Disponibilidad
|
||||
1. **Implementar Redis Replica**: Configurar Redis Cluster o Sentinel
|
||||
2. **Monitoreo**: Alertas inmediatas cuando `metrics.redisBlacklistFailures > 0`
|
||||
3. **Health Checks**: Verificar estado de Redis antes de despliegues
|
||||
4. **Graceful Degradation**: Cache en memoria como último recurso
|
||||
|
||||
## API Changes
|
||||
|
||||
### Nuevas Funciones Exportadas
|
||||
```typescript
|
||||
// Obtener métricas actuales
|
||||
export function getBlacklistMetrics(): {
|
||||
redisBlacklistFailures: number;
|
||||
redisBlacklistConsecutiveFailures: number;
|
||||
redisBlacklistSuccesses: number;
|
||||
circuitBreakerOpens: number;
|
||||
}
|
||||
|
||||
// Resetear métricas (útil para testing)
|
||||
export function resetBlacklistMetrics(): void
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
```typescript
|
||||
class AuthenticationError extends Error {
|
||||
message: 'Unable to verify token status. Service temporarily unavailable.'
|
||||
}
|
||||
```
|
||||
|
||||
## Tests Unitarios
|
||||
|
||||
Archivo: `backend/tests/redis.client.test.ts`
|
||||
|
||||
**14 tests implementados:**
|
||||
1. ✅ Verificar token blacklisteado
|
||||
2. ✅ Verificar token no blacklisteado
|
||||
3. ✅ FAIL-CLOSED cuando Redis falla
|
||||
4. ✅ FAIL-CLOSED con múltiples fallos
|
||||
5. ✅ Retry con backoff exponencial
|
||||
6. ✅ Métricas de éxito
|
||||
7. ✅ Blacklist exitoso en Redis
|
||||
8. ✅ Fallback a cache en memoria
|
||||
9. ✅ Circuit breaker se abre después de 5 fallos
|
||||
10. ✅ Reset de contador tras éxito
|
||||
11. ✅ Nunca permite acceso con Redis caído
|
||||
12. ✅ No loguea tokens completos
|
||||
13. ✅ Tracking de métricas
|
||||
14. ✅ Reset de métricas
|
||||
|
||||
## Comandos de Verificación
|
||||
|
||||
```bash
|
||||
# TypeScript
|
||||
npm run type-check
|
||||
|
||||
# Tests
|
||||
npm test -- tests/redis.client.test.ts
|
||||
|
||||
# Build
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Lista de Verificación Pre-Deploy
|
||||
|
||||
- [ ] Redis Cluster configurado en producción
|
||||
- [ ] Alertas de métricas configuradas
|
||||
- [ ] Documentación de rollback lista
|
||||
- [ ] Comunicación al equipo sobre cambio de comportamiento
|
||||
- [ ] Monitoreo de errores 401 post-deploy
|
||||
- [ ] Plan de contingencia si hay degradación de servicio
|
||||
|
||||
## Rollback
|
||||
|
||||
Si es necesario revertir (aunque NO recomendado por riesgo de seguridad):
|
||||
|
||||
```bash
|
||||
git revert <commit-hash>
|
||||
# O manualmente: restaurar return false en catch block
|
||||
```
|
||||
|
||||
## Referencias
|
||||
|
||||
- Issue: Token blacklist bypass (fixear.md Issue #2)
|
||||
- Archivo: `backend/src/shared/database/redis.client.ts:145-157`
|
||||
- PR: N/A (cambio directo)
|
||||
|
||||
---
|
||||
|
||||
**Nota de Seguridad**: Este cambio es CRÍTICO y bloquea un vector de ataque de autenticación. No debe revertirse sin considerar las implicaciones de seguridad.
|
||||
Reference in New Issue
Block a user