# 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 # 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.