Ciberseguridad · Capítulo 17

Seguridad en el Desarrollo de Software: DevSecOps y Código Seguro

Detectar un bug de seguridad en diseño cuesta $80. El mismo bug en producción cuesta $7,600. La seguridad debe construirse en el software desde el primer día, no añadirse al final.


El Paradigma Shift-Left

Tradicional mente, la seguridad se añadía al final del ciclo de desarrollo: el equipo de seguridad auditaba el software justo antes de su lanzamiento, encontraba decenas de vulnerabilidades, y el equipo de desarrollo tenía que re-trabajar código ya finalizado bajo presión de tiempo. El resultado era predecible: muchas vulnerabilidades quedaban sin corregir, se lanzaban parches de emergencia semanas después, y los costos se disparaban.

El paradigma Shift-Left mueve las actividades de seguridad hacia las etapas más tempranas del proceso de desarrollo. El principio es simple: es mucho más barato, rápido y fácil corregir un problema cuando aún estás diseñando o codificando que después de desplegar en producción.

El costo de corregir vulnerabilidades según la fase: Según el IBM Systems Sciences Institute, corregir un defecto en la fase de diseño cuesta $80. El mismo defecto en implementación: $240. En pruebas: $960. En producción: $7,600. Una brecha de seguridad real en producción: millones de dólares en multas, remediación y daño reputacional.

El Ciclo de Vida Seguro de Desarrollo de Software (Secure SDLC)

Fase 1: Requisitos

Los requisitos de seguridad deben definirse junto con los requisitos funcionales, no después. Ejemplos de requisitos de seguridad:

Fase 2: Diseño — Modelado de Amenazas

El modelado de amenazas es el proceso sistemático de identificar qué puede salir mal en un sistema antes de construirlo. El framework más usado es STRIDE, desarrollado por Microsoft:

LetraAmenazaEjemploControl
SSpoofing (Suplantación)Atacante se hace pasar por usuario legítimoAutenticación fuerte, MFA
TTampering (Manipulación)Modificar datos en tránsito o en base de datosIntegridad: HTTPS, hashes, firmas digitales
RRepudiation (Repudio)Usuario niega haber realizado una acciónLogs firmados digitalmente, auditoría
IInformation Disclosure (Divulgación)Acceso no autorizado a datos confidencialesCifrado, control de acceso, minimización de datos
DDenial of Service (DoS)Hacer el sistema inaccesible para usuarios legítimosRate limiting, redundancia, auto-scaling
EElevation of Privilege (Escalada)Usuario sin privilegios gana acceso de administradorPrincipio de mínimo privilegio, separación de roles

Diagramas de Flujo de Datos para Modelado de Amenazas

El modelado de amenazas comienza dibujando un DFD (Data Flow Diagram) del sistema. Para un sistema de login:

Ejemplo de DFD para un sistema de login:
  1. Entidades externas: Usuario (desde internet)
  2. Procesos: Servidor web (valida input), Servidor de autenticación (verifica credenciales)
  3. Almacenes de datos: Base de datos de usuarios (credenciales hasheadas)
  4. Flujos de datos: usuario→web (credenciales), web→auth (solicitud), auth→DB (consulta)
  5. Límites de confianza: Internet / DMZ / Red interna — el tráfico que cruza estos límites es el más riesgoso

Para cada flujo que cruza un límite de confianza, aplicas STRIDE y te preguntas: ¿cómo podría ser suplantado? ¿manipulado? ¿denegado?

Fase 3: Implementación — Prácticas de Código Seguro

1. Validación de Input

La regla de oro: nunca confíes en el input del usuario. Valida siempre en el servidor, independientemente de lo que hagas en el cliente:

2. Codificación de Output (Output Encoding)

Para prevenir XSS (Cross-Site Scripting), el output debe codificarse según el contexto donde se inserta:

Código vulnerable (XSS):
<p>Hola, <?php echo $_GET['nombre']; ?></p>

Si el atacante pone <script>document.cookie</script> como nombre, el script se ejecuta en el navegador de la víctima.

Código seguro:
<p>Hola, <?php echo htmlspecialchars($_GET['nombre'], ENT_QUOTES, 'UTF-8'); ?></p>

htmlspecialchars convierte: <&lt;, >&gt;, "&quot; — el script se muestra como texto, no se ejecuta.

3. Consultas Parametrizadas (Prepared Statements)

Código vulnerable (SQL Injection):
$query = "SELECT * FROM users WHERE email='" . $email . "' AND password='" . $password . "'";
Código seguro (consulta parametrizada en PHP/PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ? AND password_hash = ?");
$stmt->execute([$email, hash_password($password)]);

Con prepared statements, el valor del parámetro nunca se interpreta como SQL — es siempre tratado como dato, nunca como comando.

4. Manejo Seguro de Errores

5. Gestión de Secretos

Regla absoluta: NUNCA hardcodear credenciales en el código fuente. Cada semana, miles de desarrolladores accidentalmente suben API keys, contraseñas de bases de datos y tokens de acceso a repositorios GitHub públicos. Bots automatizados escanean GitHub constantemente y explotan estas credenciales en minutos. AWS desactiva automáticamente las access keys que detecta en código público, pero no todos los proveedores lo hacen.

Las alternativas correctas para gestionar secretos:

Fase 4: Pruebas de Seguridad

SAST — Static Application Security Testing

Analiza el código fuente sin ejecutarlo, buscando patrones de vulnerabilidades conocidas:

DAST — Dynamic Application Security Testing

Prueba la aplicación en ejecución enviando solicitudes maliciosas y observando las respuestas:

SCA — Software Composition Analysis

Fase 5: Despliegue Seguro

Lista de Verificación para Code Review de Seguridad

Cada revisión de código (pull request) debería incluir estos 10 puntos de seguridad:

  1. ¿Todo el input del usuario es validado en el servidor (tipo, longitud, formato, rango)?
  2. ¿Todas las consultas a bases de datos usan prepared statements o ORMs?
  3. ¿El output se codifica apropiadamente según el contexto (HTML, JSON, JavaScript)?
  4. ¿Las contraseñas se hashean con bcrypt, Argon2 o scrypt (nunca MD5/SHA1)?
  5. ¿Hay algún secreto (API key, contraseña, token) hardcodeado en el código?
  6. ¿Los mensajes de error exponen información sensible del sistema?
  7. ¿Se verifican los permisos de autorización en cada endpoint que accede a datos sensibles?
  8. ¿Se registran los eventos de seguridad relevantes (login, cambio de contraseña, acceso a datos sensibles)?
  9. ¿Hay alguna dependencia nueva que no ha sido escaneada en busca de CVEs?
  10. ¿El código nuevo introduce alguna superficie de ataque que no existía antes?

El Programa de Security Champions

Un modelo organizacional efectivo es el de Security Champions: designar uno o dos desarrolladores por equipo que reciban formación avanzada en seguridad y actúen como embajadores del equipo de seguridad dentro de los equipos de desarrollo. No son expertos en seguridad — son desarrolladores con conocimientos de seguridad suficientes para resolver el 80% de los problemas cotidianos sin escalar al equipo centralizado de seguridad.

Los beneficios: la seguridad escala con los equipos de desarrollo, los problemas se resuelven más rápido porque el security champion conoce el contexto del código, y se crea una cultura de seguridad distribuida en lugar de un cuello de botella centralizado.

Resumen / Summary