La mayoría de los equipos tiene requisitos de seguridad en alguna parte. Viven en una página de wiki, un PDF de políticas o una hoja de cálculo que se escribió una vez para una auditoría. Los desarrolladores no los leen mientras construyen, porque no están donde ocurre el trabajo. El trabajo ocurre en los tickets.
La solución es sencilla y un poco aburrida: pon el caso de abuso en el mismo ticket que la historia de usuario. Si la historia dice lo que quiere un usuario legítimo, el caso de abuso dice lo que quiere otra persona de la misma funcionalidad. Ambos se refinan, se estiman y se prueban juntos.
Qué es un caso de abuso
Una historia de usuario tiene una forma conocida: como cliente, quiero exportar mis facturas para poder enviárselas a mi contable. Un caso de abuso invierte el actor y el objetivo: como otro cliente con sesión iniciada, quiero exportar las facturas de otra persona para poder leer sus datos de facturación.
No es un threat model. Es un único mal uso concreto de una funcionalidad, escrito en lenguaje llano y lo bastante pequeño para caber en la descripción del ticket. El threat model es donde razonas sobre todo el sistema; el abuse case es donde ese razonamiento llega a la persona que escribe el código.
Los buenos abuse cases comparten tres rasgos:
- Un actor concreto. Otro tenant, un visitante sin autenticar, un agente de soporte, una integración comprometida. No "un hacker".
- Un objetivo concreto. Leer datos, cambiar estado, gastar dinero, denegar el servicio, escalar un rol.
- Un resultado comprobable. Puedes escribir la prueba que demuestra que no funciona.
Una plantilla que cabe en un ticket
Que sea lo bastante corto para que nadie se lo salte. Este es el bloque que sugerimos añadir a tu plantilla de historias:
## Abuse cases
- As [actor], I want to [misuse], so that [gain].
Expected: [what the system does instead]
Test: [unit | integration | QA | manual]
## Security acceptance criteria
- [ ] Object-level access checked on every export request
- [ ] Export is rate-limited per account
- [ ] Export events are logged with actor and object id
La línea "Expected" es la importante. Convierte una preocupación en un requisito. "Alguien podría exportar las facturas de otras personas" es una preocupación. "Pedir un id de factura que pertenece a otra cuenta devuelve 404 y escribe un evento de auditoría" es un requisito que un desarrollador puede construir y QA puede probar.
De dónde salen los casos de abuso
No necesitas un ingeniero de seguridad en cada sesión de refinamiento. Necesitas una lista corta de preguntas que el equipo repasa en cada historia. Cubren la mayoría de las funcionalidades:
- ¿De quién son estos datos? Si la historia toca un objeto de un usuario o tenant, escribe el abuse case del "otro usuario".
- ¿Quién puede cambiarlo? Si la historia escribe estado, escribe el abuse case del "rol inferior".
- ¿Cuánto nos cuesta? Si la historia envía correo, llama a una API de pago o genera ficheros, escribe el caso de "hacerlo diez mil veces".
- ¿En qué confía? Si la historia acepta un fichero, una URL, un webhook o texto libre, escribe el caso de "entrada hostil".
- ¿Quién lo negará? Si la historia mueve dinero o permisos, escribe el caso de "yo no fui", que normalmente significa logging.
Para los requisitos en sí, OWASP ASVS es un buen menú. Elige los controles que encajen con los abuse cases que escribiste y enlaza el punto de ASVS en los criterios de aceptación. Copiar el estándar entero en tu backlog no ayuda a nadie.
Un ejemplo práctico
Toma una historia de una funcionalidad de invitación a equipos: como admin, quiero invitar a un compañero por email, para que pueda unirse a mi espacio de trabajo. Al ejecutar los prompts sale esto:
| Prompt | Abuse case | Esperado |
|---|---|---|
| De quién son los datos | Un miembro del workspace A envía una invitación al workspace B | El endpoint de invitación comprueba que quien llama pertenece al workspace de destino |
| Quién puede cambiarlo | Un viewer invita a alguien como admin | Quien llama no puede conceder un rol superior al suyo |
| Cuánto cuesta | Un script envía miles de invitaciones a direcciones arbitrarias | Límite de frecuencia por workspace y por usuario; las invitaciones caducan |
| En qué confía | El token de invitación es adivinable o reutilizable | Token de un solo uso, aleatorio, con límite de tiempo y ligado al email |
Cuatro filas, quizá diez minutos de conversación. Cada fila se convierte en un criterio de aceptación y, idealmente, en un test automatizado. Ese es todo el método.
Hacer que se mantenga
El método falla en silencio cuando los casos de abuso se convierten en una casilla que marcar. Algunos hábitos ayudan:
- Definition of ready. Una historia que toca datos, roles o dinero no está lista sin al menos un caso de abuso.
- Definition of done. El caso de abuso tiene una prueba, o una nota explícita de por qué queda cubierto en otro sitio.
- Revisa los fallos. Cuando un pentest o un informe encuentra algo, pregunta a qué historia pertenecía y si un caso de abuso lo habría detectado. Añade el patrón a la página compartida.
- Alimenta el threat model. Los casos de abuso que se repiten apuntan a una debilidad de diseño. Llévalos de vuelta a la arquitectura y arréglalo una vez.
Piénsalo como la hoja de inspección que viaja con la pieza a lo largo de la línea, en lugar de un manual guardado en la oficina.
Qué hacer el lunes
- Añade el bloque de caso de abuso a tu plantilla de historia.
- Imprime los cinco prompts y úsalos en la próxima sesión de refinamiento.
- Elige las tres historias del sprint actual que tocan datos de usuario y escribe ya sus casos de abuso.
- Acuerda con QA que cada caso de abuso tenga un test, aunque sea manual.
- Tras un mes, mira la página compartida y comprueba qué patrones se repiten. Esas son tus próximas conversaciones de diseño.
Dónde encaja en la línea
En la torre (en desarrollo):