Ya sabemos qué es el ASVS y que BazarNube apunta al Nivel 2. Toca abrir el catálogo y trabajar con los requisitos reales. En esta lección recorreremos los capítulos de requisitos más relevantes para una aplicación web como BazarNube, aprenderemos a leer un requisito verificable con precisión y —lo más útil de todo— mapearemos los hallazgos del Top Ten del módulo 3 a requisitos ASVS concretos. Ese mapeo es el que convierte el backlog disperso de BazarNube en una checklist verificable y ordenada por capítulos.

Contenido

  1. Cómo leer un requisito verificable
  2. V2 – Autenticación
  3. V3 – Gestión de sesiones
  4. V4 – Control de acceso
  5. V5 – Validación, sanitización y codificación
  6. V6 – Criptografía almacenada
  7. V7 – Manejo de errores y logging
  8. V8/V9 – Protección de datos y comunicaciones
  9. V14 – Configuración
  10. Mapa: hallazgos Top Ten de BazarNube → requisitos ASVS

Cómo leer un requisito verificable

Antes de recorrer capítulos, fijemos el método de lectura. Un requisito ASVS se lee identificando cuatro cosas:

V5.3.3  "Verificar que la codificacion de salida sensible al contexto
         se realiza cerca o por el interprete al que va destinada."
         Niveles: L1 L2 L3   CWE-116

1. QUE afirma          -> "se hace codificacion de salida por contexto"
2. COMO se comprueba   -> revisar el codigo de renderizado/plantillas
3. EN QUE NIVEL aplica -> L1, L2 y L3 (obligatorio ya desde L1)
4. QUE debilidad cubre -> CWE-116 (codificacion incorrecta de salida)

Regla práctica: si no puedes responder "cumple / no cumple / no aplica" tras leerlo, no lo has terminado de verificar. Cada requisito es un caso de prueba, no una recomendación. Con ese método, recorramos los capítulos clave.

V2 – Autenticación

Reúne los requisitos sobre credenciales, su ciclo de vida y protección frente a abuso. Cubre el territorio de A07 (Fallos de autenticación) del Top Ten.

Requisito Texto (resumido) Nivel
V2.1.1 Las contraseñas tienen al menos 12 caracteres L1–L3
V2.1.7 Las contraseñas se contrastan contra listas de comprometidas L1–L3
V2.2.1 Existen controles anti-automatización (fuerza bruta, credential stuffing) L1–L3

Ejemplo de verificación de V2.1.7 en el backend Node de BazarNube:

// V2.1.7: rechazar contrasenas presentes en listas de filtradas
const pwnedCount = await checkBreachedPassword(password); // p.ej. k-anonymity
if (pwnedCount > 0) {
  return res.status(400).json({
    error: 'Esta contrasena aparece en filtraciones conocidas. Elige otra.'
  });
}
// V2.1.1: longitud minima
if (password.length < 12) {
  return res.status(400).json({ error: 'Minimo 12 caracteres.' });
}

V3 – Gestión de sesiones

Requisitos sobre cómo se crean, transportan, expiran e invalidan los tokens de sesión. Complementa a V2 en el territorio de A07.

Requisito Texto (resumido) Nivel
V3.2.1 Se generan tokens de sesión nuevos tras autenticarse (anti fixation) L1–L3
V3.3.1 El logout y la expiración invalidan realmente el token L1–L3
V3.4.1 Las cookies de sesión llevan atributos Secure, HttpOnly y SameSite L1–L3

Ejemplo de configuración de cookie de sesión que satisface V3.4.1 en Express:

// V3.4.1: cookie de sesion endurecida
res.cookie('sid', sessionId, {
  httpOnly: true,   // no accesible desde JavaScript (mitiga robo por XSS)
  secure: true,     // solo se envia por HTTPS
  sameSite: 'lax',  // mitiga CSRF en navegacion cross-site
  maxAge: 1000 * 60 * 30 // expiracion (apoya V3.3.x)
});

V4 – Control de acceso

El capítulo de autorización: quién puede acceder a qué. Cubre el territorio de A01 (Control de acceso roto), incluidos los IDOR que BazarNube sufría.

Requisito Texto (resumido) Nivel
V4.1.1 Las reglas de control de acceso se aplican en el servidor de confianza L1–L3
V4.1.3 Principio de mínimo privilegio: solo se accede a lo autorizado L1–L3
V4.2.1 Se verifica la propiedad del recurso antes de acceder (anti-IDOR) L1–L3

Ejemplo de verificación de V4.2.1 corrigiendo el IDOR de los pedidos de BazarNube:

// V4.2.1: comprobar propiedad del recurso, no confiar en el ID del cliente
const pedido = await Pedido.findById(req.params.id);
if (!pedido || pedido.usuarioId !== req.user.id) {
  return res.status(404).end(); // 404, no 403, para no revelar existencia
}
res.json(pedido);

V5 – Validación, sanitización y codificación

El capítulo que concentra la defensa frente a inyección y XSS. Cubre el territorio de A03 (Inyección) y del XSS del módulo 3.

Requisito Texto (resumido) Nivel
V5.1.1 La entrada se valida contra un esquema/lista de permitidos L1–L3
V5.3.3 Codificación de salida sensible al contexto (anti-XSS) L1–L3
V5.3.4 Se usan consultas parametrizadas / ORM seguro (anti-inyección SQL) L1–L3

Ejemplo de V5.3.4 sustituyendo la concatenación de SQL de BazarNube:

// MAL (inyeccion): const q = `SELECT * FROM productos WHERE nombre='${nombre}'`;
// V5.3.4: consulta parametrizada
const { rows } = await db.query(
  'SELECT * FROM productos WHERE nombre = $1',
  [nombre]
);

V6 – Criptografía almacenada

Requisitos sobre cifrado en reposo, gestión de claves y aleatoriedad. Cubre el territorio de A02 (Fallos criptográficos).

Requisito Texto (resumido) Nivel
V6.2.1 Los datos sensibles se cifran en reposo L1–L3
V6.2.3 Se usan algoritmos y modos aprobados, no obsoletos L2–L3
V6.4.1 Las claves y secretos se gestionan con un almacén seguro (no en código) L2–L3

Ejemplo de V6.4.1: los secretos no viven en el repositorio.

// V6.4.1: la clave se lee de un secret manager / variable de entorno,
// nunca hardcodeada en el codigo fuente
const dbKey = process.env.DB_ENCRYPTION_KEY; // inyectada por el secret store
if (!dbKey) throw new Error('Falta DB_ENCRYPTION_KEY en el entorno');

V7 – Manejo de errores y logging

Requisitos sobre registrar eventos de seguridad sin filtrar datos sensibles. Cubre el territorio de A09 (Fallos de registro y monitorización).

Requisito Texto (resumido) Nivel
V7.1.1 No se registran datos sensibles (credenciales, tarjetas) en los logs L1–L3
V7.2.1 Se registran los eventos de seguridad relevantes (login, acceso denegado) L2–L3
V7.3.1 Los logs están protegidos frente a manipulación y son analizables L2–L3
// V7.2.1: registrar evento de seguridad; V7.1.1: sin datos sensibles
logger.security('login_fallido', {
  usuarioHash: hash(email),   // no el email en claro; nunca la contrasena
  ip: req.ip,
  ts: Date.now()
});

V8/V9 – Protección de datos y comunicaciones

  • V8 (Protección de datos): minimización, retención, protección de datos sensibles en cliente y memoria. Cubre parte de A02 y A04 (Diseño inseguro).
  • V9 (Comunicaciones): TLS bien configurado, cifrado en tránsito, sin protocolos débiles.
Requisito Texto (resumido) Nivel
V8.1.1 Se protegen datos sensibles frente a caché no autorizada L2–L3
V8.3.1 Se minimiza y controla la retención de datos personales L2–L3
V9.1.1 Toda comunicación usa TLS; sin fallback a texto plano L1–L3
V9.1.2 Se usan versiones y suites TLS actuales; sin protocolos obsoletos L2–L3

V14 – Configuración

Endurecimiento del despliegue: cabeceras de seguridad, dependencias, secretos, valores por defecto. Cubre A05 (Configuración incorrecta) y A06 (Componentes vulnerables).

Requisito Texto (resumido) Nivel
V14.3.2 Se eliminan configuraciones y cuentas por defecto innecesarias L1–L3
V14.4.1 Se envían cabeceras de seguridad HTTP (CSP, HSTS, X-Content-Type-Options...) L1–L3
V14.2.1 Las dependencias están al día y sin vulnerabilidades conocidas L1–L3
// V14.4.1: cabeceras de seguridad con helmet en Express
app.use(helmet({
  contentSecurityPolicy: { directives: { defaultSrc: ["'self'"] } },
  hsts: { maxAge: 31536000, includeSubDomains: true }
}));

Mapa: hallazgos Top Ten de BazarNube → requisitos ASVS

Este es el entregable central de la lección: convertir el backlog del módulo 3 (organizado por riesgos A01–A10) en requisitos ASVS verificables (organizados por capítulos V). Cada fila toma un hallazgo real de BazarNube y lo ancla a los requisitos que hay que verificar.

Hallazgo BazarNube (M3) Riesgo Top Ten Requisitos ASVS a verificar Cap.
IDOR en /pedidos/:id A01 V4.1.1, V4.2.1 V4
Secretos y clave de cifrado en el repo A02 V6.2.1, V6.4.1 V6
Datos de pago sin cifrar en reposo A02 V6.2.1, V8.1.1 V6/V8
SQL por concatenación en búsqueda A03 V5.1.1, V5.3.4 V5
Falta de threat modeling en el checkout A04 V1.1.x V1
Sin cabeceras de seguridad / defaults inseguros A05 V14.3.2, V14.4.1 V14
Librería con CVE conocido A06 V14.2.1 V14
XSS reflejado en el buscador A03/XSS V5.3.3, V5.3.4 V5
Contraseñas débiles y sin anti-fuerza bruta A07 V2.1.1, V2.1.7, V2.2.1 V2
Sesión no se invalida al cerrar sesión A07 V3.3.1, V3.4.1 V3
Sin registro de eventos de seguridad A09 V7.2.1, V7.3.1 V7
SSRF en "imagen desde URL" A10 V5.2.6, V12.6.x V5/V12

Con este mapa, BazarNube ya no tiene "un montón de fixes sueltos": tiene una checklist ASVS por capítulos, con nivel asociado y estado verificable por cada fila. Ese es el insumo directo de la siguiente lección, donde lo convertiremos en un plan de implementación.

graph LR
  TT[Hallazgos Top Ten M3] --> MAP[Mapeo a requisitos ASVS]
  MAP --> CHK[Checklist por capitulos V]
  CHK --> VER[Verificacion cumple no-cumple]

Errores Comunes y Consejos

  • Leer el requisito como consejo y no como test. Si tras leerlo no sabes decir cumple/no cumple, no lo has verificado; te falta mirar código o probar.
  • Validar solo en el cliente. V4.1.1 y V5.1.1 exigen aplicar control de acceso y validación en el servidor; el front es ayuda de UX, no control de seguridad.
  • Confundir codificación de salida con validación de entrada. Son requisitos distintos (V5.3 vs V5.1) y ambos hacen falta: validar entrada no exime de codificar la salida.
  • Guardar secretos en el repositorio. V6.4.1 lo prohíbe explícitamente; usa un secret store o variables de entorno inyectadas.
  • Consejo: trabaja capítulo a capítulo, no requisito aleatorio. Terminar V2 entero da una imagen de cumplimiento mucho más útil que picotear requisitos sueltos de varios capítulos.

Ejercicios

Ejercicio 1. Toma el hallazgo "XSS reflejado en el buscador" de BazarNube. Indica a qué capítulo(s) y requisito(s) ASVS lo mapearías y explica por qué intervienen tanto validación de entrada como codificación de salida.

Ejercicio 2. Lee este requisito y responde qué comprobarías en el código de BazarNube para marcarlo "cumple": "V3.4.1 – Verificar que las cookies de sesión usan los atributos Secure, HttpOnly y SameSite."

Ejercicio 3. El hallazgo "secretos en el repositorio" se mapeó a V6.4.1. Propón dos evidencias concretas que presentarías a un auditor para demostrar que ahora BazarNube cumple ese requisito.

Soluciones

Solución 1. Se mapea al capítulo V5 (Validación, sanitización y codificación), principalmente a V5.3.3 (codificación de salida sensible al contexto) y, de forma complementaria, a V5.1.1 (validación de entrada). Intervienen ambos porque son defensas distintas y acumulativas: validar la entrada reduce la superficie (rechazar caracteres/estructuras inesperadas), pero no basta, porque datos legítimos pueden contener caracteres peligrosos; la protección determinante frente a XSS es codificar la salida según el contexto (HTML, atributo, JS) en el punto de renderizado. Cumplir solo uno deja hueco; el ASVS exige ambos.

Solución 2. Buscaría en el código donde se emite la cookie de sesión (por ejemplo la config de express-session o el res.cookie('sid', ...)) y comprobaría que están puestos los tres atributos: httpOnly: true (no accesible desde JS, mitiga robo por XSS), secure: true (solo por HTTPS) y sameSite (lax o strict, mitiga CSRF). Si los tres están presentes en todos los caminos que crean la cookie, el requisito se marca cumple; si falta alguno o hay una ruta que emite la cookie sin ellos, no cumple.

Solución 3. (1) Evidencia de configuración: captura del secret manager / variables de entorno mostrando que DB_ENCRYPTION_KEY y demás secretos se inyectan en tiempo de ejecución, más el fragmento de código que los lee de process.env sin valores hardcodeados. (2) Evidencia de proceso/histórico: resultado de un escaneo de secretos (por ejemplo un secret scanner en CI) sobre el repositorio actual devolviendo cero hallazgos, y confirmación de que las claves antiguas expuestas fueron rotadas. Ambas juntas demuestran que los secretos ni están en el código ni son ya los que estuvieron expuestos.

Conclusión

Los requisitos del ASVS se organizan en capítulos temáticos —V2 autenticación, V3 sesiones, V4 control de acceso, V5 validación y codificación, V6 criptografía, V7 logging, V8/V9 datos y comunicaciones, V14 configuración— y cada uno se lee como un caso de prueba con respuesta cumple/no cumple/no aplica. Lo más valioso para BazarNube ha sido mapear los hallazgos del Top Ten del módulo 3 a requisitos ASVS concretos, transformando un backlog de riesgos sueltos en una checklist verificable por capítulos y niveles.

Tenemos el estándar, el nivel objetivo (L2) y la checklist mapeada. Falta lo que convierte todo esto en resultados: cómo integrarlo en el día a día del proyecto. En la última lección del módulo, 04-04 Implementación de ASVS en Proyectos, veremos cómo usar la checklist como criterios de aceptación, cuándo verificar manual o automáticamente, cómo dejar evidencias y trazabilidad, y trazaremos un plan práctico paso a paso para el backlog de BazarNube.

Curso de OWASP: Directrices y Estándares para la Seguridad en Aplicaciones Web

Módulo 1: Introducción a OWASP

Módulo 2: Principales Proyectos de OWASP

Módulo 3: OWASP Top Ten 2021 en Profundidad

Módulo 4: OWASP ASVS (Application Security Verification Standard)

Módulo 5: OWASP SAMM (Software Assurance Maturity Model)

Módulo 6: OWASP ZAP (Zed Attack Proxy)

Módulo 7: Buenas Prácticas y Recomendaciones

Módulo 8: Ejercicios Prácticos y Casos de Estudio

Módulo 9: Evaluación y Certificación

© Copyright 2026. Todos los derechos reservados