Mapeo OWASP Top 10 al Sistema de Turnos Medicos¶
Proposito¶
Mapear cada vulnerabilidad del OWASP Top 10 (2021) a riesgos concretos en nuestro sistema, con mitigaciones especificas y verificacion en codigo.
Cuando usarlo¶
- Al hacer threat modeling de nuevas features.
- En code review para verificar que no se introducen vulnerabilidades.
- Como referencia para el security checklist.
OWASP Top 10 (2021)¶
A01: Broken Access Control¶
Riesgo en nuestro sistema:
- Un paciente modifica el :bookingId en la URL y accede al booking de otro paciente.
- Un paciente accede a endpoints de admin sin tener el rol.
- Un medico ve la informacion de pacientes que no son suyos.
Mitigacion:
// CORRECTO: Verificar ownership en cada query
async getBooking(bookingId: string, userId: string, userRole: string) {
const booking = await this.bookingRepo.findOne(bookingId);
if (!booking) throw new AppError('BOOKING_NOT_FOUND', 404);
// Verificar que el usuario tiene acceso
if (userRole === 'PATIENT' && booking.patientId !== userId) {
throw new AppError('FORBIDDEN', 403);
}
if (userRole === 'DOCTOR' && booking.doctorId !== userId) {
throw new AppError('FORBIDDEN', 403);
}
return booking;
}
// INCORRECTO: Confiar en que el cliente solo pide sus bookings
async getBooking(bookingId: string) {
return this.bookingRepo.findOne(bookingId); // Cualquiera puede ver cualquier booking!
}
Verificacion: Tests de integracion que validan que un paciente NO puede acceder a bookings de otro.
A02: Cryptographic Failures¶
Riesgo en nuestro sistema: - Passwords almacenados en plaintext o con hash debil (MD5, SHA1). - Datos de salud transmitidos sin encriptacion. - JWT firmado con secreto debil o algoritmo inseguro.
Mitigacion: - Passwords: bcrypt con cost >= 12. - Transporte: HTTPS obligatorio (HSTS). - JWT: RS256 con par de claves asimetricas (no HS256 con secreto compartido). - BD: Encriptacion at-rest (DigitalOcean managed lo incluye).
Verificacion: Unit test que verifica que el password guardado NO es igual al plaintext.
A03: Injection¶
Riesgo en nuestro sistema: - SQL injection en busqueda de medicos por nombre. - NoSQL injection (si usaramos MongoDB). - Template injection en emails de notificacion.
Mitigacion:
// CORRECTO: Parametros preparados (TypeORM lo hace automaticamente)
const doctors = await this.doctorRepo
.createQueryBuilder('d')
.where('d.lastName ILIKE :name', { name: `%${searchTerm}%` })
.getMany();
// INCORRECTO: Concatenacion de strings en queries
const doctors = await this.doctorRepo
.query(`SELECT * FROM doctors WHERE last_name LIKE '%${searchTerm}%'`);
// SQL injection: searchTerm = "'; DROP TABLE doctors; --"
Verificacion: Test con input malicioso: "'; DROP TABLE bookings; --" no causa dano.
A04: Insecure Design¶
Riesgo en nuestro sistema: - No hay rate limiting y un bot reserva todos los turnos. - No hay validacion de reglas de negocio en el servidor (solo en frontend). - El flujo de reset password permite enumeracion de emails.
Mitigacion: - Rate limiting en todos los endpoints criticos. - Validacion de TODAS las reglas de negocio en el backend. - Mensajes genericos que no revelan informacion.
Verificacion: Specs incluyen seccion de seguridad. Threat model antes de implementar.
A05: Security Misconfiguration¶
Riesgo en nuestro sistema:
- Stack traces expuestos en produccion.
- CORS abierto a todos los origenes (*).
- Headers de seguridad faltantes.
- Puertos de BD expuestos a internet.
Mitigacion:
// NestJS: Error handler global para produccion
@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse();
if (exception instanceof AppError) {
return response.status(exception.statusCode).json({
error: { code: exception.code, message: exception.message }
});
}
// En produccion: NO exponer detalles internos
return response.status(500).json({
error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' }
});
}
}
Verificacion: Smoke test en staging verifica que un error 500 no muestra stack trace.
A06: Vulnerable and Outdated Components¶
Riesgo en nuestro sistema: - Dependencias de npm con vulnerabilidades conocidas. - Node.js version sin soporte. - PostgreSQL version sin parches de seguridad.
Mitigacion:
- npm audit en CI pipeline (falla en high/critical).
- Dependabot o Renovate para updates automaticos.
- Managed PostgreSQL (DigitalOcean aplica parches).
Verificacion: Stage de Security Scan en CI pipeline.
A07: Identification and Authentication Failures¶
Riesgo en nuestro sistema: - Brute force de passwords sin proteccion. - Tokens JWT que no expiran. - Sesiones que no se invalidan al cambiar password.
Mitigacion: - Bloqueo temporal despues de 5 intentos fallidos. - Access token expira en 15 min, refresh token en 7 dias. - Al cambiar password, revocar todos los refresh tokens existentes. - Politica de password: 8+ chars, 1 mayuscula, 1 numero.
Verificacion: Tests de integracion para bloqueo de cuenta y expiracion de tokens.
A08: Software and Data Integrity Failures¶
Riesgo en nuestro sistema: - Dependencias de npm comprometidas (supply chain attack). - CI/CD pipeline sin verificacion de integridad. - Updates sin firma ni verificacion.
Mitigacion:
- Lockfile (package-lock.json) en version control.
- npm ci (no npm install) en CI para respetar lockfile.
- Revisar PRs de Dependabot antes de merge.
A09: Security Logging and Monitoring Failures¶
Riesgo en nuestro sistema: - Login fallidos no se loggean (no detectas ataques). - No hay alertas para patrones sospechosos. - Logs no tienen suficiente contexto para investigar.
Mitigacion: - Loggear: login fallidos, accesos denegados, cambios de password, creacion de admins. - Alertar: > 50 login fallidos en 10 min, > 100 errores 403 en 5 min. - Formato JSON estructurado con userId, IP, action, timestamp.
Verificacion: Ver observability-strategy.md.
A10: Server-Side Request Forgery (SSRF)¶
Riesgo en nuestro sistema: - Bajo (no hay funcionalidad que haga requests a URLs proporcionadas por el usuario). - Riesgo futuro si se agrega importacion de recetas desde URL o integracion con sistemas externos.
Mitigacion (preventiva): - Si se agrega funcionalidad que hace requests a URLs externas: validar contra allowlist de dominios. - No permitir URLs a IPs internas (127.0.0.1, 10.x, 192.168.x).
Resumen de Prioridades¶
| OWASP | Prioridad para nuestro sistema | Estado |
|---|---|---|
| A01: Broken Access Control | CRITICA | Implementar en v1 |
| A02: Cryptographic Failures | ALTA | Implementar en v1 |
| A03: Injection | ALTA | TypeORM mitiga por default |
| A04: Insecure Design | ALTA | Specs con seccion de seguridad |
| A05: Security Misconfiguration | MEDIA | Checklist en deploy |
| A06: Vulnerable Components | MEDIA | CI pipeline |
| A07: Auth Failures | CRITICA | Implementar en v1 |
| A08: Integrity Failures | BAJA | Lockfile + npm ci |
| A09: Logging Failures | MEDIA | Implementar en v1 |
| A10: SSRF | BAJA | No aplica aun |
Checklist de Completitud¶
- Las 10 categorias OWASP mapeadas al sistema
- Riesgos concretos identificados
- Mitigaciones con codigo de ejemplo
- Prioridades definidas
- Revisada por otro ingeniero
Archivos relacionados¶
- threat-model-template.md - Threat model
- security-checklist.md - Checklist por feature
- ../01-specs/feature-user-auth.spec.md - Spec de auth
- ../07-devops-and-platform/ci-cd-pipeline.md - Pipeline con security scan