Dominio 5a: Prácticas de codificación segura
Dominio 5a: Prácticas de codificación segura
El Dominio 5 — Secure Software Implementation pesa un 14% del examen y es donde el diseño seguro se convierte en código real. ISC2 lo divide en seis subdominios; este capítulo cubre los tres que tratan de cómo escribir código seguro:
- 5.1 Adherir a prácticas relevantes de codificación segura (estándares, patrones defensivos).
- 5.3 Implementar controles de seguridad (según el riesgo identificado).
- 5.4 Abordar riesgos de seguridad identificados (corregir, mitigar y gestionar la deuda).
Los subdominios 5.2 (análisis de código), 5.5 (componentes) y 5.6 (build seguro) se tratan en el capítulo 8.
💡 Tip de examen: el CSSLP no te pide arreglar sintaxis ni encontrar el bug de una función en pantalla. Te pregunta qué principio o control aplica, dónde en el ciclo se introduce el defecto y cuál es la mitigación correcta. Piensa como arquitecto de seguridad, no como quien depura una línea.
flowchart LR
A[5.1 Prácticas de<br/>codificación segura] --> D[Código seguro]
B[5.3 Implementar<br/>controles] --> D
C[5.4 Abordar riesgos<br/>identificados] --> D
D --> E[Análisis y build<br/>Cap. 8]
1. La mentalidad de la codificación defensiva
La codificación segura parte de una premisa: toda entrada es hostil hasta que se demuestre lo contrario y todo componente puede fallar. En lugar de confiar en que el usuario, la red o un sistema vecino se comporten bien, el código valida, controla y falla de forma segura.
Cuatro ideas transversales sostienen todo el dominio:
| Idea | Qué significa en el código |
|---|---|
| Defense in depth | Nunca depender de un solo control; validar en múltiples capas |
| Fail secure | Ante un error o duda, denegar el acceso, no concederlo |
| Least privilege | El proceso corre con los permisos mínimos; nada de root “por si acaso” |
| Economía de mecanismo | Código simple y auditable; la complejidad esconde vulnerabilidades |
💡 Tip de examen: si una pregunta describe un componente que falla y deja el sistema abierto (concede acceso al caer), la respuesta correcta casi siempre invoca fail secure / fail closed. Excepción típica: sistemas de seguridad de la vida humana (puertas de emergencia) que deben fail safe / fail open para no atrapar personas.
2. Validación de entradas
La validación de entradas es el control preventivo más importante contra la familia de inyecciones y contra la corrupción de datos. La regla base: valida todo dato que cruza un límite de confianza (trust boundary).
2.1 Allowlist vs blocklist
| Enfoque | Definición | Veredicto |
|---|---|---|
| Allowlist (whitelist) | Se define lo que es válido y se rechaza el resto | Preferido — seguro por defecto |
| Blocklist (blacklist) | Se define lo que es peligroso y se acepta el resto | Frágil — siempre olvidas un caso |
El allowlist es superior porque el conjunto de entradas válidas es finito y conocido, mientras que el conjunto de entradas maliciosas es infinito y evoluciona. Un blocklist que filtra <script> no detiene <img onerror=...>.
2.2 Qué validar
- Tipo: ¿es un entero, una fecha, un email?
- Longitud / rango: límites mínimos y máximos (evita buffer overflow y DoS).
- Formato: expresiones regulares anclas (
^...$) para el patrón completo. - Consistencia de negocio: una fecha de nacimiento no puede ser futura.
2.3 Canonicalización primero
La canonicalización es reducir una entrada a su forma más simple y estándar antes de validarla. Es un paso crítico y frecuentemente olvidado: un atacante puede codificar el mismo payload de muchas formas (%2e%2e%2f, ..%c0%af, doble URL-encoding) para evadir un filtro que solo mira la forma literal.
flowchart LR
A[Entrada cruda] --> B[Canonicalizar<br/>decodificar, normalizar]
B --> C{¿Coincide con<br/>allowlist?}
C -->|Sí| D[Procesar]
C -->|No| E[Rechazar + log]
💡 Tip de examen: el orden correcto es canonicalizar → validar → usar. Validar antes de canonicalizar es un error clásico que permite bypass de filtros mediante encoding. Relaciónalo con path traversal y con la debilidad CWE-22.
2.4 ¿Dónde validar?
- Siempre en el servidor. La validación en el cliente (JavaScript) es solo experiencia de usuario; un atacante la salta con curl o Burp.
- En el límite de confianza más cercano al dato, y de nuevo en cada capa que reciba datos de otra (defense in depth).
- La validación del lado del cliente no es un control de seguridad; nunca es suficiente por sí sola.
3. Output encoding y sanitización
Validar la entrada no basta: el mismo dato puede ser inofensivo en un contexto y peligroso en otro. El output encoding neutraliza los datos en el momento de emitirlos hacia un intérprete (navegador, shell, motor SQL).
3.1 Encoding contextual
El encoding debe corresponder al contexto de salida. El mismo carácter < se codifica distinto según dónde se coloque:
| Contexto de salida | Técnica |
|---|---|
| Cuerpo HTML | HTML entity encoding (<, >) |
| Atributo HTML | Attribute encoding + comillas |
| JavaScript | Unicode/JS encoding (\uXXXX) |
| URL / query string | Percent-encoding (URL encoding) |
| CSS | CSS hex encoding |
Usar el encoding equivocado (por ejemplo, HTML-encoding dentro de un contexto JavaScript) deja el XSS abierto.
3.2 Encoding vs sanitización vs escaping
- Encoding: transforma caracteres a una representación segura para el intérprete de destino (reversible en el render). Es la defensa principal contra XSS reflejado y almacenado.
- Sanitización: elimina o neutraliza partes peligrosas del dato, dejando solo lo permitido. Se usa cuando el dato debe contener marcado (p. ej. un editor de texto enriquecido: se sanitiza con una librería como un HTML sanitizer que aplica allowlist de etiquetas).
- Escaping / parametrización: en el contexto de consultas, se separa el código de los datos (ver §7).
💡 Tip de examen: ante XSS, la mejora primaria es output encoding contextual, complementada con validación de entrada y una Content Security Policy (CSP) como defensa en profundidad. Para contenido que legítimamente lleva HTML, la respuesta es sanitización con allowlist, no encoding.
4. Manejo seguro de errores y excepciones
Los errores son inevitables; cómo se manejan determina si filtran información o dejan el sistema en un estado inseguro.
4.1 Fail secure
Cuando ocurre una excepción no prevista, el estado por defecto debe ser denegar. Un bloque de autorización que concede acceso en la rama de error es una vulnerabilidad grave (CWE-636, “Not Failing Securely”).
4.2 No filtrar información en los mensajes
Los mensajes de error dirigidos al usuario deben ser genéricos. Los detalles técnicos —stack traces, consultas SQL, rutas de archivos, versiones de framework— alimentan el reconocimiento del atacante (mapea a CWE-209, Information Exposure Through an Error Message).
| Mostrar al usuario | Registrar internamente |
|---|---|
| ”Ocurrió un error. ID: 8f3a2” | Stack trace completo |
| ”Credenciales inválidas” | Qué campo falló y por qué |
| Página de error genérica | Consulta, parámetros, contexto |
- Los mensajes de autenticación deben ser uniformes: “usuario o contraseña incorrectos” (nunca “ese usuario no existe”, que permite enumeración de cuentas).
- Centraliza el manejo de errores (un handler global) para no dejar rutas sin cubrir.
💡 Tip de examen: un mensaje de login que distingue “usuario inexistente” de “contraseña incorrecta” habilita account enumeration. La respuesta correcta es un mensaje genérico e idéntico para ambos casos.
5. Logging seguro
El logging es a la vez un control de detección y una posible fuente de fuga. La clave está en qué se registra y qué no.
5.1 Qué registrar
- Eventos de seguridad: inicios de sesión (éxito y fallo), cambios de privilegios, accesos denegados, cambios de configuración.
- Suficiente contexto para trazabilidad: timestamp (con zona), identidad, origen, acción, resultado.
- Un identificador de correlación para seguir una transacción entre servicios.
5.2 Qué NO registrar (jamás)
| Nunca en logs | Por qué |
|---|---|
| Contraseñas, PINs, secretos | Convierte el log en un botín |
| Tokens de sesión / API keys | Permiten secuestro de sesión |
| Datos de tarjeta (PAN, CVV) | Viola PCI DSS |
| PII/PHI sin necesidad | Viola GDPR/HIPAA |
| Datos criptográficos (llaves) | Rompe toda la protección |
5.3 Integridad y protección del log
- Los logs deben ser append-only y protegidos contra manipulación; idealmente enviados a un servidor central (SIEM) fuera del alcance del atacante.
- Cuidado con la log injection / log forging (CWE-117): un atacante que inyecta saltos de línea puede falsificar entradas. Neutraliza los caracteres de control antes de escribir.
- Define retención acorde a requisitos legales y de negocio.
💡 Tip de examen: dos trampas frecuentes juntas: (1) registrar secretos/PII es fuga de datos; (2) escribir entrada de usuario sin neutralizar habilita log injection. Un buen log es completo en eventos de seguridad pero estéril en datos sensibles.
6. Gestión de sesiones, autenticación y credenciales
6.1 Gestión de sesiones
- Genera identificadores de sesión con un CSPRNG (generador criptográficamente seguro), largos y no predecibles.
- Regenera el ID de sesión tras autenticarse (previene session fixation).
- Marca las cookies con
HttpOnly,SecureySameSite. - Aplica timeouts de inactividad y absolutos; invalida la sesión en el servidor al cerrar (no basta borrar la cookie).
6.2 Almacenamiento seguro de credenciales
Las contraseñas nunca se almacenan en claro ni cifradas de forma reversible. Se almacena un hash con estas propiedades:
- Función de hashing lenta y adaptativa: bcrypt, scrypt o Argon2 (Argon2id es el estado del arte). Están diseñadas para ser costosas y resistir ataques con GPU/ASIC.
- Salt único por usuario: valor aleatorio que se concatena antes de hashear; anula rainbow tables y evita que dos usuarios con la misma contraseña compartan hash.
- Pepper (opcional): secreto global almacenado aparte (p. ej. en un HSM), como capa adicional.
- Factor de trabajo ajustable al alza con el tiempo.
| No usar | Usar |
|---|---|
| MD5, SHA-1 | Argon2id / bcrypt / scrypt |
| SHA-256 “a secas” para passwords | Función lenta con salt |
| Cifrado reversible (AES) | Hashing unidireccional |
| Sal fija/compartida | Salt aleatorio por usuario |
💡 Tip de examen: SHA-256 es excelente para integridad, pero inadecuado para contraseñas porque es rápido. Para credenciales, la respuesta correcta es siempre un KDF lento con salt (bcrypt/scrypt/Argon2). Distingue hashing (unidireccional, para verificar) de cifrado (reversible, para confidencialidad).
flowchart LR
A[Contraseña] --> B[+ salt único]
B --> C[Argon2id / bcrypt<br/>factor de trabajo alto]
C --> D[(Hash almacenado)]
E[Login: contraseña] --> F[Mismo salt + KDF]
F --> G{¿Hash coincide?}
G -->|Sí| H[Autenticado]
G -->|No| I[Rechazar - mensaje genérico]
7. Inyecciones y parametrización
Las inyecciones ocurren cuando datos no confiables se interpretan como código/comandos por un intérprete. Son la familia de vulnerabilidades más dañina y la mitigación es transversal: separar código de datos.
| Tipo de inyección | Intérprete atacado | Mitigación primaria |
|---|---|---|
| SQL injection | Motor de base de datos | Consultas parametrizadas / prepared statements |
| Command injection | Shell del SO | Evitar shell; APIs que separan comando y args; allowlist |
| LDAP injection | Directorio LDAP | Escapado LDAP + validación |
| XPath injection | Parser XML/XPath | Consultas XPath parametrizadas |
| NoSQL injection | Motor NoSQL | Operadores tipados, evitar concatenar |
7.1 La regla de oro: parametrización
Las consultas parametrizadas (prepared statements) son la defensa definitiva contra SQL injection porque el motor recibe la estructura de la consulta por separado de los valores; los datos nunca se compilan como parte del comando.
-- Vulnerable: concatenación
"SELECT * FROM users WHERE user = '" + input + "'"
-- Seguro: parametrizado (el driver separa código y dato)
SELECT * FROM users WHERE user = ?
Complementos (defense in depth): stored procedures bien escritos, ORM que parametriza por defecto, least privilege en la cuenta de BD (el usuario de la app no debería poder hacer DROP), y validación de entrada como capa adicional.
💡 Tip de examen: para SQL injection, la respuesta canónica es parameterized queries / prepared statements. El escaping manual y los blocklists de comillas son mitigaciones débiles. Para command injection, lo ideal es no invocar un shell: usar APIs que reciban el ejecutable y sus argumentos como lista.
8. Concurrencia y race conditions
Cuando varios hilos o procesos acceden a un recurso compartido sin la sincronización adecuada, aparecen race conditions con consecuencias de seguridad.
8.1 TOCTOU
Time-of-Check to Time-of-Use (CWE-367) es la race condition clásica: el programa verifica una condición (p. ej. “¿el usuario puede escribir este archivo?”) y después actúa, pero entre ambos instantes el atacante cambia el recurso (reemplaza el archivo por un symlink a /etc/passwd). La ventana entre check y use es la vulnerabilidad.
sequenceDiagram
participant App
participant Atacante
participant FS as Sistema de archivos
App->>FS: 1. Check: ¿puedo usar /tmp/data?
FS-->>App: OK, permisos válidos
Atacante->>FS: 2. Reemplaza /tmp/data por symlink
App->>FS: 3. Use: escribe en /tmp/data
Note over FS: Escribe en el objetivo del symlink
8.2 Mitigaciones
- Operaciones atómicas: hacer check y use en una sola operación indivisible (p. ej. abrir el archivo con flags atómicos y operar sobre el descriptor, no sobre la ruta).
- Locks / mutex / semáforos para serializar el acceso a recursos compartidos.
- Minimizar el estado compartido mutable; preferir inmutabilidad.
💡 Tip de examen: TOCTOU = brecha temporal entre verificar y usar. La mitigación es atomicidad (o bloqueo), no “verificar dos veces”. Reconócelo cuando el escenario mencione un archivo/recurso comprobado y luego usado por ruta.
9. Manejo seguro de memoria
En lenguajes de bajo nivre como C/C++, la gestión manual de memoria es fuente de vulnerabilidades críticas de ejecución de código.
| Debilidad | CWE | Descripción |
|---|---|---|
| Buffer overflow | CWE-120/787 | Escribir más allá del búfer, sobrescribiendo memoria adyacente |
| Use-after-free | CWE-416 | Usar un puntero a memoria ya liberada |
| Double free | CWE-415 | Liberar dos veces el mismo bloque |
| Integer overflow | CWE-190 | Desbordamiento que lleva a asignaciones erróneas |
9.1 Defensas
- Lenguajes memory-safe: Rust, Go, Java, C#, Python gestionan la memoria y eliminan de raíz la mayoría de estas clases. Migrar componentes críticos a un lenguaje memory-safe es hoy una recomendación de agencias como CISA y la NSA.
- Si se usa C/C++: funciones seguras (
strncpy,snprintf), comprobación de límites, y protecciones del compilador/SO: ASLR, DEP/NX, stack canaries, CFG. - Validar longitudes y rangos antes de copiar (enlaza con validación de entrada, §2).
💡 Tip de examen: si el escenario permite elegir tecnología para código crítico expuesto a entradas no confiables, un lenguaje memory-safe elimina categorías enteras de bugs. Las protecciones de compilador (ASLR, DEP, canaries) son mitigaciones, no eliminaciones: elevan el costo del exploit pero no cierran la debilidad de fondo.
10. OWASP Top 10 2021
El OWASP Top 10 es la referencia de concienciación sobre los riesgos más críticos en aplicaciones web. La edición 2021 introdujo tres categorías nuevas y reordenó las existentes.
| ID | Categoría | Mitigación clave |
|---|---|---|
| A01 | Broken Access Control | Deny by default, controles del lado servidor, RBAC/ABAC, pruebas de autorización |
| A02 | Cryptographic Failures | Cifrar datos sensibles en tránsito y reposo, algoritmos fuertes, gestión de llaves |
| A03 | Injection (incluye XSS) | Parametrización, output encoding contextual, validación con allowlist |
| A04 | Insecure Design | Threat modeling, patrones seguros, requisitos de seguridad desde el diseño |
| A05 | Security Misconfiguration | Hardening, deshabilitar defaults, revisar configs, mínima superficie |
| A06 | Vulnerable and Outdated Components | SCA, inventario (SBOM), parcheo, eliminar dependencias sin uso |
| A07 | Identification and Authentication Failures | MFA, gestión de sesión robusta, políticas de credenciales |
| A08 | Software and Data Integrity Failures | Firmas, verificación de integridad, CI/CD confiable (deserialización insegura) |
| A09 | Security Logging and Monitoring Failures | Registrar eventos de seguridad, alertar, monitorear |
| A10 | Server-Side Request Forgery (SSRF) | Allowlist de destinos, validar URLs, segmentación de red |
💡 Tip de examen: A04 Insecure Design fue la gran novedad de 2021 y liga directamente con el Dominio 4: los defectos de diseño no se arreglan codificando mejor; requieren threat modeling y patrones seguros aguas arriba. Recuerda también que XSS quedó absorbido dentro de A03 Injection y que SSRF (A10) entró por votación de la comunidad.
flowchart TD
subgraph Nuevas_2021
A04[A04 Insecure Design]
A08[A08 Integrity Failures]
A10[A10 SSRF]
end
A01[A01 Broken Access Control<br/>subió al #1] --> Top[OWASP Top 10 2021]
A03[A03 Injection<br/>absorbe XSS] --> Top
Nuevas_2021 --> Top
11. CWE Top 25
Mientras el OWASP Top 10 organiza riesgos a alto nivel, la CWE (Common Weakness Enumeration) es un catálogo taxonómico de debilidades concretas de software mantenido por MITRE. El CWE Top 25 Most Dangerous Software Weaknesses es la lista anual de las debilidades más peligrosas, calculada a partir de datos reales de CVEs (frecuencia × severidad).
Ejemplos destacados que aparecen recurrentemente en el Top 25:
| CWE | Debilidad |
|---|---|
| CWE-79 | Cross-Site Scripting (XSS) |
| CWE-89 | SQL Injection |
| CWE-787 | Out-of-bounds Write |
| CWE-416 | Use After Free |
| CWE-20 | Improper Input Validation |
| CWE-78 | OS Command Injection |
| CWE-22 | Path Traversal |
| CWE-352 | Cross-Site Request Forgery (CSRF) |
💡 Tip de examen: distingue los dos catálogos: CWE = debilidad (la causa, tipo de defecto), CVE = vulnerabilidad (una instancia concreta y explotable en un producto específico, con identificador). El OWASP Top 10 agrupa riesgos; el CWE Top 25 enumera tipos de debilidad. No memorices los 25 números; entiende qué es cada catálogo y cómo se relacionan.
12. CERT Secure Coding Standards
Los CERT Secure Coding Standards (del CERT Coordination Center, Carnegie Mellon SEI) son conjuntos de reglas y recomendaciones específicas por lenguaje para escribir código sin las debilidades conocidas. Existen estándares para C, C++, Java, Android y Perl.
- Reglas: normas cuya violación puede producir una vulnerabilidad explotable (obligatorias).
- Recomendaciones: buenas prácticas que mejoran la seguridad y la calidad.
- Cada regla está mapeada a las CWE relacionadas y a su severidad/probabilidad.
Adoptar un estándar de codificación segura por lenguaje da al equipo un criterio objetivo y auditable para las revisiones de código y para configurar las herramientas de análisis estático.
💡 Tip de examen: cuando la pregunta busque una fuente autoritativa de reglas de codificación por lenguaje, la respuesta es CERT Secure Coding Standards (junto con OWASP y las guías de MISRA para sistemas embebidos/seguros). Son insumo directo del subdominio 5.1 (adherir a prácticas de codificación segura).
12.5 Otras debilidades de implementación frecuentes
Además de las grandes familias, hay debilidades que aparecen a nivel de código y que ISC2 espera que reconozcas y mitigues:
| Debilidad | Riesgo | Mitigación en el código |
|---|---|---|
| Insecure deserialization | Ejecución remota al deserializar datos no confiables (OWASP A08) | No deserializar datos no confiables; usar formatos de datos (JSON) sin gadgets; validar tipos e integridad (firma) |
| File upload inseguro | Subir un ejecutable/web shell | Validar tipo real (magic bytes), renombrar, almacenar fuera del webroot, límite de tamaño, escaneo antimalware |
| SSRF | El servidor hace peticiones a destinos internos (OWASP A10) | Allowlist de destinos, resolver y validar la URL, bloquear rangos internos/metadata |
| CSRF | Acción no deseada con la sesión de la víctima | Tokens anti-CSRF, SameSite, verificar origen |
| Open redirect | Redirigir a un dominio malicioso | Allowlist de destinos de redirección; no confiar en parámetros |
| Mass assignment | Sobrescribir campos sensibles (rol, saldo) vía binding automático | Allowlist de campos vinculables (DTOs explícitos) |
💡 Tip de examen: la deserialización insegura es la debilidad estrella de A08 (Integrity Failures) y una vía común de RCE; la regla es no deserializar datos no confiables. Para SSRF, la defensa correcta es allowlist de destinos + validación de URL, no un blocklist de IPs.
13. Implementar controles y abordar los riesgos identificados
Los subdominios 5.3 y 5.4 conectan el código con la gestión de riesgos que viene de fases anteriores (requisitos, threat modeling).
13.1 Controles según el riesgo (5.3)
Un control de seguridad se implementa en respuesta a un riesgo identificado, no “porque sí”. La intensidad del control debe ser proporcional al riesgo y al valor del activo. Los controles se clasifican por función:
| Tipo | Función | Ejemplo en código |
|---|---|---|
| Preventivo | Impedir que ocurra | Validación de entrada, parametrización |
| Detectivo | Descubrir que ocurrió | Logging de seguridad, alertas |
| Correctivo | Restaurar tras el incidente | Rollback, invalidar sesiones |
| Disuasivo | Desincentivar | Banners, rate limiting visible |
| Compensatorio | Sustituto cuando el ideal no es viable | WAF mientras se corrige el código |
13.2 Defense in depth aplicada al código
Ningún control es infalible, así que se apilan capas independientes. Para XSS, por ejemplo: validación de entrada + output encoding contextual + CSP + cookies HttpOnly. Si una capa falla, la siguiente contiene el daño.
13.3 Abordar hallazgos y deuda de seguridad (5.4)
Cuando SAST, revisión de código o pentesting reportan hallazgos, hay que decidir el tratamiento del riesgo (igual que en gestión de riesgos):
- Corregir (remediar): eliminar la debilidad en el código. Preferido.
- Mitigar: reducir el impacto/probabilidad con un control compensatorio (WAF, hardening) cuando la corrección no es inmediata.
- Transferir: por ejemplo, mediante servicios o seguros (raro a nivel de código).
- Aceptar: solo con aprobación formal del dueño del riesgo, documentada y con fecha de revisión.
La deuda de seguridad (security debt) es el conjunto de hallazgos conocidos y no corregidos. Debe rastrearse (en el bug tracker, con severidad y SLA de remediación), priorizarse por riesgo, y no dejarse crecer en silencio: la deuda sin gestionar es una brecha esperando a suceder.
flowchart LR
A[Hallazgo de seguridad] --> B{¿Se puede<br/>corregir ya?}
B -->|Sí| C[Remediar en código]
B -->|No| D[Mitigar: control<br/>compensatorio]
D --> E[Registrar como<br/>deuda de seguridad]
E --> F[Priorizar por riesgo<br/>SLA de remediación]
C --> G[Verificar / retest]
F --> G
💡 Tip de examen: aceptar un riesgo es una decisión de negocio formal del dueño del riesgo, no del desarrollador. Un control compensatorio (WAF) es una mitigación temporal, no una corrección: no elimina la debilidad subyacente. La deuda de seguridad debe rastrearse y priorizarse por riesgo, nunca ignorarse.
Puntos clave
- El Dominio 5 (14%) es la traducción del diseño seguro a código; este capítulo cubre 5.1 (prácticas de codificación), 5.3 (implementar controles) y 5.4 (abordar riesgos).
- Valida toda entrada en el servidor con allowlist, tras canonicalizar; la validación del cliente no es un control de seguridad.
- Neutraliza XSS con output encoding contextual; usa sanitización con allowlist cuando el dato debe llevar HTML.
- Falla fail secure, muestra errores genéricos al usuario y registra el detalle internamente; evita account enumeration con mensajes uniformes.
- Registra eventos de seguridad pero nunca secretos ni PII; protege el log contra manipulación e inyección (CWE-117).
- Almacena contraseñas con KDF lento + salt único (Argon2id/bcrypt/scrypt), nunca con hashing rápido ni cifrado reversible.
- La defensa universal contra inyecciones es separar código de datos: consultas parametrizadas para SQL, evitar el shell para comandos.
- TOCTOU se resuelve con atomicidad/locks; los bugs de memoria se eliminan mejor con lenguajes memory-safe que con parches de compilador.
- Domina la estructura del OWASP Top 10 2021 (A04 Insecure Design y A10 SSRF como novedades, XSS dentro de A03) y distingue CWE (debilidad) de CVE (vulnerabilidad).
- Los CERT Secure Coding Standards son la referencia de reglas por lenguaje del subdominio 5.1.
- Implementa controles proporcionales al riesgo, apílalos en defense in depth, y rastrea la deuda de seguridad con SLA en lugar de ignorarla.