Saltar a contenido

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