Skip to content
This page has been auto-translated and may contain errors.View in English

Modelado de amenazas basado en funcionalidades

Un portal estudiantil agrega una nueva funcionalidad de carga de archivos. Los estudiantes pueden entregar sus tareas, y los profesores pueden dejar retroalimentación.

Suena lo bastante simple como para construirlo. Un formulario, un campo para subir archivos, un botón de enviar, una página para el profesor.

También es lo bastante simple como para modelar sus amenazas de forma adecuada.

El modelado de amenazas basado en funcionalidades toma una funcionalidad y la recorre de principio a fin. En cada paso, te preguntas qué podría salir mal y qué necesita verificar el código.

Recorre la funcionalidad

Empieza con la historia normal:

  1. Un estudiante inicia sesión.
  2. El estudiante sube un archivo.
  3. El servidor lo almacena.
  4. Un profesor abre la entrega.
  5. El profesor deja retroalimentación.
  6. El estudiante lee la retroalimentación.

Esa lista es el mapa. No necesitas un diagrama sofisticado para empezar.

Ahora marca los lugares donde un valor cruza un límite de confianza:

PasoValor que cruza el límiteQué preguntar
CargaNombre del archivo, tipo de archivo, tamaño del archivo¿El servidor verificó el archivo en sí?
AlmacenamientoRuta y metadatos¿Puede un estudiante sobrescribir el archivo de otro?
Vista del profesorId de la entrega¿Este profesor está asignado a este estudiante?
RetroalimentaciónTexto de la retroalimentación¿Puede convertirse en un script al mostrarse?
Vista del estudianteId de la retroalimentación¿Puede un estudiante leer la retroalimentación de otro?

Ahora la funcionalidad tiene forma. Puedes ver dónde corresponden las decisiones de seguridad.

Empieza con la historia, luego agrega las amenazas

Si empiezas con nombres de amenazas, el ejercicio se siente abstracto.

Si empiezas con la historia de la funcionalidad, cada amenaza tiene dónde aterrizar.

JunoRecorre la funcionalidad Empieza con la historia normal. ¿Quién inicia sesión, qué envía, a dónde va, quién lo lee después?

Luego marca los momentos en que tu aplicación recibe algo que no eligió. Esos son los puntos donde el servidor necesita hacer más preguntas.

JunoRecorre la funcionalidad El movimiento práctico es convertir la funcionalidad en filas: paso, valor, límite, verificación. Ese formato mantiene el modelo cerca del código.

Para la funcionalidad de carga, los puntos calientes son el archivo en sí, la ruta almacenada, el id de la entrega, la retroalimentación del profesor y la vista del estudiante. Cada uno se corresponde con un manejador o una decisión de almacenamiento que puedes probar.

JunoRecorre la funcionalidad Los modelos por funcionalidad funcionan porque son lo bastante pequeños como para completarlos. La contrapartida es que heredan cualquier problema estructural que el sistema ya tenga.

Si toda funcionalidad depende del mismo modelo de roles débil, seguirás encontrando la misma amenaza disfrazada de otra cosa.

Ahí es cuando el modelo de la funcionalidad ya cumplió su propósito y te está diciendo que hace falta programar una revisión más amplia del sistema. Es molesto, sí. Pero sale más barato que fingir que el quinto hallazgo duplicado es información nueva.

Convierte las amenazas en verificaciones

Un modelo de funcionalidad no debería terminar siendo solo una lista de preocupaciones.

Para la funcionalidad de carga, una preocupación podría ser:

Un estudiante podría subir algo inseguro.

Eso es cierto, pero es demasiado vago como para construir algo a partir de ahí. Convirtámoslo en una verificación:

  • Limita el tamaño del archivo antes de almacenarlo.
  • Permite solo los tipos de archivo esperados.
  • Genera el nombre del archivo almacenado en el servidor.
  • Almacena los archivos fuera del directorio público de la aplicación.
  • Verifica que el profesor esté asignado al estudiante antes de mostrar el archivo.

Ahora el modelo puede convertirse en criterios de aceptación.

Una amenaza se vuelve útil cuando el siguiente desarrollador puede convertirla en código o en una prueba.

JunoConvierte las amenazas en verificaciones Una preocupación dice qué te da miedo. Una verificación dice qué va a hacer la aplicación al respecto.

"Carga insegura" es una preocupación. "Limitar el tamaño del archivo y generar el nombre del archivo almacenado en el servidor" es una verificación que alguien puede construir.

JunoConvierte las amenazas en verificaciones Escribe las verificaciones en el mismo lenguaje que el ticket. Eso mantiene el modelo vivo después de la reunión.

Por ejemplo: el profesor puede ver una entrega solo cuando el servidor confirma que ese profesor está asignado a ese estudiante. Esa frase se convierte en una verificación de ruta y en un caso de prueba sin necesidad de traducirla.

JunoConvierte las amenazas en verificaciones La verificación tiene que vivir donde se toma la decisión. Un botón deshabilitado en la interfaz del profesor es útil, pero no es el control. La ruta que sirve el archivo es el control.

Aquí es donde los sistemas antiguos se vuelven costosos. Una funcionalidad puede tener tres caminos hacia los mismos datos: la ruta web, la herramienta de administración y la exportación en segundo plano. Si la verificación está solo en uno de esos caminos, el modelo encontró una puerta y la implementación construyó una cortina.

Practícalo con la retroalimentación del profesor

Ahora usa tú mismo el mismo método.

La funcionalidad dice: los profesores pueden dejar retroalimentación en las entregas de los estudiantes.

Responde las cinco preguntas basadas en la funcionalidad antes de seguir leyendo.

  1. ¿Quién envía el valor?
  2. ¿Quién lo lee después?
  3. ¿Qué decisión importa?
  4. ¿Qué podría salir mal?
  5. ¿Qué debería verificar el código?
Compara tus respuestas
PreguntaUna respuesta razonable
¿Quién envía el valor?El profesor envía el texto de la retroalimentación.
¿Quién lo lee después?El estudiante, y posiblemente otro profesor.
¿Qué decisión importa?Solo un profesor asignado puede dejar retroalimentación.
¿Qué podría salir mal?La retroalimentación podría contener un script, o terminar en la entrega equivocada.
¿Qué debería verificar el código?La asignación en el servidor, la longitud del texto y la salida segura al mostrarse.

La pregunta 2 es la que más peso tiene y la que menos atención recibe. Identificar quién leerá un valor después es lo que te indica que se va a renderizar en una página, y eso es lo que hace que "podría contener un script" sea una pregunta que vale la pena hacerse.

Si respondes solo la pregunta 1, obtienes validación de entrada. Si respondes también la pregunta 2, obtienes además seguridad en la salida.

La solución exacta llega más adelante en el manual. Lo que importa ahora es el hábito: recorre la funcionalidad, marca el límite, escribe la verificación. Ese es todo el método.

El front end puede guiar, pero el servidor decide

La página puede ocultar los controles de retroalimentación a los profesores que no están asignados.

La ruta igual tiene que verificar la asignación, porque cualquiera puede llamar a la ruta directamente.

JunoPractícalo con la retroalimentación del profesor La retroalimentación del profesor parece solo texto en una caja, pero la funcionalidad tiene varias decisiones adentro.

¿Quién puede escribirla? ¿A qué entrega pertenece? ¿Quién puede leerla después? Pensar en seguridad es notar esas decisiones antes de que el código las responda por ti sin que te des cuenta.

JunoPractícalo con la retroalimentación del profesor La retroalimentación tiene dos formas comunes de bug: que la persona equivocada pueda escribirla, o que el texto correcto se vuelva inseguro al mostrarse después.

Eso te da dos verificaciones en lugares distintos. La autorización pertenece a la ruta que guarda la retroalimentación. La salida segura pertenece a donde se renderiza la retroalimentación. El mismo valor, distinto destino, distinta regla.

JunoPractícalo con la retroalimentación del profesor El texto almacenado es paciente. Puede quedarse tranquilo en la base de datos durante meses, y luego volverse peligroso cuando una página nueva lo renderiza en un contexto diferente.

Por eso los modelos por funcionalidad deberían nombrar los destinos, no solo las entradas. "El texto de la retroalimentación se muestra a estudiantes y profesores" es más útil que "el texto de la retroalimentación se almacena". La segunda frase te dice dónde duerme el dato. La primera te dice dónde puede despertar y arruinarte la tarde.

Hacia dónde va esto

El modelado de amenazas basado en funcionalidades es la versión del día a día de STRIDE. Puedes aplicarlo durante la planificación, escribir las verificaciones en el ticket y probarlas antes de que la funcionalidad salga a producción.

A continuación, OWASP y bugs reales cambia la línea de tiempo. En lugar de preguntar qué podría salir mal antes del lanzamiento, le pone nombre a las cosas que ya salieron mal en aplicaciones reales.