Ir al contenido

FundamentosLección 01

Pensar como defensor

Activos, amenazas y riesgo; la tríada CIA; cómo modelar amenazas con STRIDE y los principios que guían cada decisión de seguridad.

Básico14 min de lectura

Al terminar sabrás

  • Distinguir activo, amenaza, vulnerabilidad, exploit y riesgo.
  • Usar la tríada CIA para saber qué propiedad rompe un ataque.
  • Modelar las amenazas de un endpoint con STRIDE.
  • Aplicar defensa en profundidad, mínimo privilegio y "fallar cerrado".

Antes de escribir una sola línea de configuración conviene tener un modelo mental. La seguridad no consiste en “poner autenticación”; consiste en proteger cosas valiosas de gente que quiere abusar de ellas, con un coste razonable. Todo lo demás —contraseñas, tokens, filtros— son herramientas al servicio de esa idea.

TérminoQué esEjemplo en una API de notas
ActivoAlgo con valor que hay que protegerLas notas privadas, las contraseñas, la cuenta de admin
AmenazaAlgo que podría dañar un activoQue un usuario lea las notas de otro
VulnerabilidadUna debilidad que hace posible la amenazaEl endpoint GET /notes/{id} no comprueba el dueño
ExploitLa forma concreta de aprovecharlaCambiar /notes/41 por /notes/42 en la URL
RiesgoProbabilidad × impactoAlto: es trivial de explotar y expone datos privados
ControlLa medida que reduce el riesgoFiltrar la consulta por owner = usuario autenticado
Superficie de ataqueTodo lo que un atacante puede tocarEndpoints, formularios, cabeceras, ficheros subidos, dependencias

La tríada CIA: qué propiedad rompe cada ataque

Sección titulada «La tríada CIA: qué propiedad rompe cada ataque»

Casi cualquier incidente de seguridad rompe una de tres propiedades. Saber cuál te dice qué tipo de control necesitas.

CIAConfidencialidadsolo lee quien debeTLS, cifrado, control de accesoIntegridadnadie lo altera sin que se notehashes, firmas, MACDisponibilidadfunciona cuando se necesitarate limiting, redundancia
Confidencialidad, integridad y disponibilidad: las tres propiedades que protege la seguridad de la información.
  • Confidencialidad: solo lee quien debe leer. La rompe una fuga de datos, un token interceptado o un endpoint que devuelve más campos de la cuenta.
  • Integridad: los datos y las acciones no se alteran sin que se note. La rompe un precio modificado en el carrito, un JWT manipulado o una transferencia que el usuario no pidió (CSRF).
  • Disponibilidad: el sistema responde cuando se le necesita. La rompe una avalancha de peticiones al login, una consulta que tarda minutos o un fichero gigante subido a propósito.

A menudo se añaden dos más: autenticidad (sabes quién envió algo) y no repudio (quien lo hizo no puede negarlo, gracias a firmas y registros de auditoría).

El modelado de amenazas suena a burocracia, pero en su versión mínima son cuatro preguntas que puedes hacerte frente a una pizarra en 20 minutos:

  1. 1¿Qué estamos construyendo?un diagrama con componentes, datos y fronteras de confianza
  2. 2¿Qué puede salir mal?STRIDE sobre cada flecha y cada caja
  3. 3¿Qué vamos a hacer?mitigar, aceptar, transferir o eliminar
  4. 4¿Lo hicimos bien?tests, revisión, pentest

La pieza más útil del primer paso es la frontera de confianza (trust boundary): la línea donde los datos pasan de algo que no controlas (el navegador, la red, otro servicio) a algo que sí. Todo lo que cruza esa línea es sospechoso hasta que lo validas.

STRIDE es una lista de seis categorías de amenazas. Cada letra rompe una propiedad, y cada una tiene un control típico:

LetraAmenazaPropiedad que rompeEjemploControl típico
SSpoofing (suplantación)AutenticidadIniciar sesión como otro usuarioAutenticación fuerte, MFA
TTampering (manipulación)IntegridadCambiar el owner en el JSON de una peticiónValidación, firmas, no confiar en el cliente
RRepudiation (repudio)No repudio“Yo no borré esa nota”Registro de auditoría
IInformation disclosure (fuga)ConfidencialidadUn stack trace con rutas y versiones internasMínima exposición, cifrado
DDenial of serviceDisponibilidadMiles de intentos de login por segundoRate limiting, límites de tamaño
EElevation of privilegeAutorizaciónUn usuario normal llama a /adminAutorización en el servidor, mínimo privilegio

Ningún control es perfecto. Por eso se apilan: si uno falla, el siguiente todavía protege.

Redfirewall, WAF, rate limiting

TransporteTLS / HTTPS

Autenticación¿quién eres?

Autorización¿puedes hacer esto con este recurso?

Validaciónentrada y salida

Datos
Cada capa asume que la anterior puede fallar. Un atacante tiene que atravesarlas todas.

Cada usuario, servicio y proceso recibe solo los permisos que necesita, y solo durante el tiempo que los necesita. El usuario de base de datos de tu API no necesita DROP TABLE; un token para leer notas no necesita el scope de escritura; un job nocturno no necesita ser administrador.

Un sistema bien diseñado empieza cerrado y abres explícitamente lo que hace falta. Y cuando algo falla —una excepción, un servicio caído, un dato inesperado— la respuesta segura es denegar, no permitir.

Evita

boolean canDelete(Long noteId, String user) {
try {
return notes.ownerOf(noteId).equals(user);
} catch (Exception e) {
return true; // "si falla, que no moleste"
}
}

Prefiere

boolean canDelete(Long noteId, String user) {
try {
return notes.ownerOf(noteId).equals(user);
} catch (Exception e) {
log.warn("No se pudo verificar el dueño", e);
return false; // ante la duda, no
}
}

Todo lo que llega del cliente puede estar manipulado: parámetros, cabeceras, cookies, el cuerpo JSON, el nombre de un fichero. El frontend puede ocultar un botón, pero el servidor es el único que decide.

  • Economía del mecanismo: cuanto más simple es un control, más fácil es verificar que funciona. Un filtro JWT casero de 200 líneas tiene más sitios donde equivocarse que una línea de configuración de un componente auditado.
  • Sin seguridad por oscuridad: el sistema debe ser seguro aunque el atacante conozca su diseño (principio de Kerckhoffs). Lo único secreto deben ser las claves, no el algoritmo ni la URL “difícil de adivinar” del panel de administración.

Mini lab · 15 min

STRIDE sobre un endpoint

Objetivo: Aplicar STRIDE al endpoint DELETE /api/notes/{id} de una API de notas y proponer un control para cada amenaza.

Imagina una API donde cada usuario tiene notas privadas y un administrador puede borrar cualquiera. El endpoint DELETE /api/notes/{id} recibe un token en la cabecera Authorization.

  1. Escribe una amenaza concreta para cada letra de STRIDE.
  2. Para cada una, indica qué propiedad rompe y qué control la mitiga.
  3. Ordena las seis por riesgo (probabilidad × impacto). ¿Cuál atacarías primero si fueras el atacante?
Pista

Piensa en qué pasa si cambias el número de la URL, si el token es de otra persona, si nadie registra quién borró qué, y si alguien llama al endpoint diez mil veces por segundo.

Mostrar respuestaOcultar respuesta
LetraAmenaza concretaPropiedadControl
SUsar un token robado de otro usuarioAutenticidadTokens de vida corta, HTTPS, MFA en el login
TEnviar DELETE /api/notes/42 siendo dueño solo de la 41IntegridadComprobar el dueño en el servidor (findByIdAndOwner)
RUn admin borra una nota y luego lo niegaNo repudioRegistro de auditoría con usuario, IP y hora
ILa respuesta de error revela si la nota 42 existe (“no es tuya” vs “no existe”)ConfidencialidadResponder 404 en ambos casos
DBorrado masivo con un scriptDisponibilidadRate limiting por usuario, borrado lógico
EUn usuario normal invoca la ruta de borrado de adminAutorizaciónReglas de autorización en el servidor, no solo ocultar el botón

La más probable y grave suele ser la T/E por IDOR (cambiar el id de la URL): es trivial de explotar y la vulnerabilidad número uno en APIs según OWASP. Por eso la lección de autorización le dedica una sección entera.