El mòdul 7 va acabar amb una promesa: teníem el procés complet assemblat —S-SDLC, threat modeling, DevSecOps, capacitació i un stack d'eines per a BazarNube— i arribava el moment d'aplicar-lo amb les mans. Aquest mòdul compleix aquesta promesa. En aquestes quatre lliçons deixem de descriure el procés i l'executem sobre BazarNube: dos exercicis guiats d'identificació i remediació, i dos casos d'estudi d'anàlisi d'incident i de millora. Comencem pel principi de qualsevol feina d'AppSec: trobar allò que està malament. En aquest laboratori reps un fragment real de l'aplicació —diversos endpoints Node/Express, un component React i la seva configuració— i la teva tasca és identificar, classificar i documentar cada vulnerabilitat com ho faria un analista, combinant revisió de codi i escaneig amb ZAP (vist a fons al mòdul 6). No reparis res encara: això és l'exercici 2. Aquí només cacem i cataloguem.

Contingut

  1. Objectiu i entorn del laboratori
  2. Metodologia: com abordar la identificació
  3. El checklist basat en Top Ten i ASVS
  4. El codi a revisar: endpoints, component i configuració
  5. Com documentar una troballa i registrar-la al backlog
  6. Errors comuns i consells
  7. Exercicis
  8. Conclusió

Objectiu i entorn del laboratori

Treballes com a AppSec a BazarNube al costat de la Lucía (backend lead) i el Marc (frontend). La SRE ha desplegat a l'entorn de staging una nova branca del servei de comandes i catàleg, i abans d'aprovar el merge l'has de revisar. Disposes de dues entrades d'informació:

  • El codi font del fragment (a sota), sobre el qual faràs una revisió manual.
  • Un escaneig ZAP de la instància de staging ja en marxa, l'informe del qual consultaràs per confirmar troballes i trobar les que el codi no revela a simple vista.

L'objectiu del laboratori no és explotar res a fons, sinó identificar i classificar: per cada problema, determinar la seva categoria de l'OWASP Top Ten 2021, la seva severitat, l'evidència que el sustenta i el requisit ASVS que incompleix. El resultat és una llista de troballes a punt per entrar al backlog BZN-xxx, exactament el format que ZAP ja alimentava a 06-03.

Recordatori ètic: tot això es fa sobre la nostra aplicació al nostre staging. La identificació de vulnerabilitats només és legítima sobre sistemes propis o amb autorització explícita, tal com vam establir al mòdul 1.

Metodologia: com abordar la identificació

Improvisar porta a oblits. Seguim un mètode repetible que combina les dues tècniques:

graph LR
    A[Entendre el context] --> B[Revisio de codi guiada per checklist]
    B --> C[Escaneig ZAP passiu i actiu]
    C --> D[Correlacionar codi i alertes]
    D --> E[Triatge: confirmar o descartar]
    E --> F[Documentar cada troballa BZN]
  1. Entendre el context. Què fa aquest codi? Quines dades manega? A BazarNube hi ha comandes, preus, dades personals i pagaments: qualsevol fallada aquí toca diners o PII.
  2. Revisió de codi guiada per checklist. No llegeixis el codi "a veure què trobo"; recorre'l amb una llista de preguntes concretes (secció següent). Presta atenció especial als encreuaments de límit de confiança del threat model de 07-02: entrada de l'usuari, consultes a BD, crides a tercers.
  3. Escaneig ZAP. L'escaneig passiu detecta capçaleres i cookies mal configurades; l'actiu prova injecció, XSS o path traversal. No reexpliquem ZAP: l'utilitzem com a 06-03.
  4. Correlacionar. Cada alerta de ZAP ha de poder assenyalar-se al codi, i cada sospita del codi ha d'intentar confirmar-se dinàmicament. El que apareix per totes dues vies és gairebé sempre real.
  5. Triatge. Descarta falsos positius amb evidència (reproduir la petició), no per intuïció.
  6. Documentar. Una troballa sense fitxa reproduïble no existeix per a l'equip.

El checklist basat en Top Ten i ASVS

Aquest és el guió de preguntes amb què recorrem el codi. Cada fila apunta a una categoria del Top Ten i als capítols ASVS que verifiquen aquell control.

# Pregunta de revisió Top Ten ASVS
1 Es comprova que l'usuari és propietari de l'objecte que demana (comanda, factura)? A01 V4 (Access Control)
2 Alguna consulta concatena entrada de l'usuari en SQL/comandes? A03 V5 (Validation/Encoding)
3 Es renderitza contingut de l'usuari com a HTML sense escapar? A03 V5
4 Hi ha secrets encastats al codi o algorismes criptogràfics febles? A02 V6 (Cryptography)
5 L'app fa peticions a URLs que controla l'usuari? A10 V12 (SSRF)
6 S'accedeix a fitxers amb noms que vénen de l'usuari? A01 V4, V12
7 Falten capçaleres de seguretat (CSP, HSTS) o helmet? A05 V14 (Config)
8 Les cookies duen HttpOnly, Secure i SameSite? A05 V3 (Session)
9 Els errors exposen stack traces o detalls interns? A05 V7 (Errors/Logging)
10 Hi ha rate limiting en autenticació i endpoints sensibles? A07 V2 (Authentication)

El codi a revisar: endpoints, component i configuració

A continuació, el fragment lliurat. Llegeix-lo amb el checklist a la mà abans de mirar la solució.

config.js (configuració del backend)

// config.js — configuracio del servei de comandes
module.exports = {
  jwtSecret: 'bazarnube-2021',        // usat per signar els tokens de sessio
  jwtAlg: 'HS256',
  db: { host: 'db', user: 'app', password: 'app', ssl: false },
  cookie: { httpOnly: false, secure: false }, // opcions de la cookie de sessio
};

app.js (arrencada d'Express)

const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();

app.use(express.json());
app.use(cookieParser());
// (no s'instal·la helmet ni es defineix cap Content-Security-Policy)

app.use(require('./routes/orders'));
app.use(require('./routes/catalog'));

// Gestor d'errors global
app.use((err, req, res, next) => {
  res.status(500).json({ error: err.message, stack: err.stack }); // detall intern al client
});

app.listen(3000);

routes/orders.js

const router = require('express').Router();
const db = require('../db');
const path = require('path');
const auth = require('../middleware/auth'); // valida el JWT i posa req.user

// Detall d'una comanda
router.get('/api/comandes/:id', auth, async (req, res) => {
  const { rows } = await db.query('SELECT * FROM orders WHERE id = $1', [req.params.id]);
  res.json(rows[0]);   // retorna la comanda sense comprovar que sigui de l'usuari
});

// Descarrega de la factura en PDF
router.get('/api/invoices', auth, (req, res) => {
  const file = req.query.file; // ex. ?file=2026-000123.pdf
  res.sendFile(path.join('/var/bazarnube/invoices', file));
});

module.exports = router;

routes/catalog.js

const router = require('express').Router();
const db = require('../db');
const auth = require('../middleware/auth');

// Cercador de productes
router.get('/api/products/search', async (req, res) => {
  const q = req.query.q;
  const sql = `SELECT id, name, price FROM products WHERE name LIKE '%${q}%'`;
  const { rows } = await db.query(sql);  // es concatena q directament
  res.json(rows);
});

// Importar producte: descarrega la imatge des d'una URL indicada pel venedor
router.post('/api/products/import', auth, async (req, res) => {
  const { imageUrl } = req.body;
  const resp = await fetch(imageUrl); // es descarrega qualsevol URL que envii l'usuari
  const buffer = Buffer.from(await resp.arrayBuffer());
  // ... desa el buffer com a imatge del producte
  res.json({ ok: true });
});

module.exports = router;

ProductReviews.jsx (component React)

export function ProductReviews({ reviews }) {
  // reviews[].body es text lliure escrit per altres compradors
  return (
    <ul>
      {reviews.map((r) => (
        <li key={r.id} dangerouslySetInnerHTML={{ __html: r.body }} />
      ))}
    </ul>
  );
}

Extracte de l'informe ZAP (staging)

L'escaneig de 06-03 sobre aquesta branca va retornar, entre d'altres, aquestes alertes passives i actives:

[High]   SQL Injection             GET /api/products/search (q)
[High]   Path Traversal            GET /api/invoices (file)
[Medium] CSP: Header Not Set        /
[Low]    Cookie No HttpOnly Flag    Set-Cookie: session
[Low]    Application Error Disclosure  500 amb stack trace

Com documentar una troballa i registrar-la al backlog

Una troballa útil és reproduïble i accionable. Cada fitxa BZN-xxx inclou els mateixos camps que ZAP ja ens donava, més el requisit ASVS incomplert:

  • ID: BZN-xxx.
  • Títol: què és, en una línia.
  • Categoria OWASP: A01–A10 del Top Ten 2021.
  • Severitat: Crítica/Alta/Mitjana/Baixa (per risc = impacte x probabilitat).
  • Ubicació: fitxer/endpoint i línia.
  • Evidència: la petició o el fragment de codi que ho prova.
  • Requisit ASVS: el control que incompleix (per a l'exercici 2).
  • Com s'ha detectat: revisió de codi, ZAP, o totes dues (major confiança).

Exemple de fitxa ben redactada:

ID:          BZN-101
Titol:       IDOR a GET /api/comandes/:id (falta control de propietat)
Categoria:   A01 Broken Access Control
Severitat:   Alta (acces a PII i comandes d'altres clients)
Ubicacio:    routes/orders.js, handler GET /api/comandes/:id
Evidencia:   Autenticat com a client A, GET /api/comandes/778 (comanda de B)
             retorna 200 amb les dades de B. No es filtra per req.user.id.
ASVS:        V4.1.1 / V4.2.1 (autoritzacio a nivell d'objecte)
Deteccio:    Revisio de codi (ZAP no ho marca: requereix logica de negoci)

Fixa't en el matís de l'última línia: ZAP no detecta l'IDOR perquè no sap qui hauria de poder veure què. Les fallades de lògica d'autorització es cacen gairebé sempre per revisió de codi, mentre que injecció, XSS o path traversal apareixen també a l'escaneig dinàmic. Per això el mètode combina totes dues tècniques: cap de les dues per si sola no n'hi ha prou.

Errors Comuns i Consells

  • Refiar-se només de l'escàner. ZAP no troba IDOR ni secrets encastats ni criptografia feble. Si la teva identificació es limita a l'informe de ZAP, se t'escaparà A01 i bona part d'A02. Combina sempre amb revisió de codi.
  • Confondre quantitat amb qualitat. Reportar cent alertes passives trivials enterra les dues crítiques de veritat. Prioritza per risc real, com al triatge de 06-03.
  • No reproduir abans de reportar. Una troballa sense evidència reproduïble es discuteix eternament. Adjunta la petició o la línia exacta.
  • Ignorar el dangerouslySetInnerHTML. React escapa per defecte, així que molts revisors assumeixen que "no hi ha XSS". Aquesta API concreta desactiva la protecció: és un imant d'A03.
  • Consell: revisa sempre primer els encreuaments de límit de confiança (entrada d'usuari, consultes a BD, crides a tercers, accés a fitxers). Allà viu la immensa majoria de les troballes, com anticipava el threat model de 07-02.

Exercicis

Exercici 1. Recorre el fragment amb el checklist i elabora la llista completa de troballes: per cadascuna, indica endpoint/fitxer, categoria del Top Ten 2021 i severitat. N'hauries de trobar almenys nou.

Exercici 2. Per a l'endpoint GET /api/invoices, redacta la fitxa BZN-140 completa (tots els camps) i indica el payload concret que faries servir com a evidència.

Exercici 3. Justifica per què l'IDOR de comandes no apareix a l'informe de ZAP i quina tècnica sí que el detecta. Generalitza: quines categories del Top Ten se li escapen estructuralment a un DAST?

Solucions

Solució 1. Llista de troballes del laboratori:

ID Troballa Ubicació OWASP 2021 Severitat Detecció
BZN-134 SQLi per concatenació de q catalog.js /search A03 Injection Crítica Codi + ZAP
BZN-101 IDOR: comanda d'un altre usuari orders.js /comandes/:id A01 Broken Access Control Alta Codi
BZN-140 Path traversal a file= orders.js /invoices A01 Broken Access Control Alta Codi + ZAP
BZN-131 SSRF: descàrrega d'URL arbitrària catalog.js /import A10 SSRF Alta Codi
BZN-087 XSS emmagatzemat via dangerouslySetInnerHTML ProductReviews.jsx A03 Injection Alta Codi
BZN-155 Secret JWT encastat i feble config.js A02 Cryptographic Failures Alta Codi
BZN-041 Sense CSP ni helmet app.js A05 Security Misconfiguration Mitjana ZAP
BZN-039 Cookie sense HttpOnly/Secure/SameSite config.js A05 Security Misconfiguration Mitjana ZAP
BZN-060 Stack trace exposat al client app.js (handler d'error) A05 Security Misconfiguration Baixa Codi + ZAP

Diversos (BZN-140, BZN-131, BZN-087, BZN-041, BZN-039, BZN-060) ja existien al backlog des de l'escaneig de 06-03: aquest exercici els confirma per revisió de codi i n'afegeix dos de nous (BZN-134, BZN-101).

Solució 2. Fitxa de BZN-140:

ID:          BZN-140
Titol:       Path Traversal a GET /api/invoices (parametre file)
Categoria:   A01 Broken Access Control
Severitat:   Alta (lectura de fitxers arbitraris del servidor)
Ubicacio:    routes/orders.js, handler GET /api/invoices
Evidencia:   GET /api/invoices?file=../../../../etc/passwd  -> 200 amb el fitxer
             sendFile uneix el path sense normalitzar ni validar que quedi dins de
             /var/bazarnube/invoices.
ASVS:        V4.1.3 / V12.3.1 (control d'acces a fitxers, path canonitzat)
Deteccio:    Revisio de codi + alerta activa de ZAP "Path Traversal"

El payload d'evidència és ?file=../../../../etc/passwd (o qualsevol ruta fora del directori de factures). Confirma la lectura arbitrària.

Solució 3. ZAP no detecta l'IDOR perquè un DAST prova entrades i respostes sense conèixer les regles de negoci: no sap que la comanda 778 pertany a un altre usuari, així que un 200 li sembla correcte. Detectar-lo requereix entendre la lògica d'autorització, cosa que es fa per revisió de codi o amb proves manuals autenticades amb dos usuaris. En general, a un DAST se li escapen de manera estructural: A01 (control d'accés/IDOR/escalada), bona part d'A02 (secrets i cripto feble al codi), A04 (fallades de disseny) i A08 (integritat), perquè depenen de context i lògica, no de patrons observables a la resposta.

Conclusió

Hem convertit un fragment de BazarNube en una llista de nou troballes prioritzades, cadascuna amb la seva categoria del Top Ten, la seva severitat, la seva evidència i el seu requisit ASVS incomplert, totes registrades com a fitxes BZN-xxx al backlog. L'important no és només la llista, sinó el mètode: context, checklist Top Ten/ASVS, revisió de codi, escaneig ZAP i correlació, amb la lliçó clau que cap tècnica per si sola no basta —l'escàner no veu l'IDOR, i la revisió manual no escala com l'escàner—. Ara tenim el diagnòstic; ens falta la cura. A la lliçó següent, 08-02, agafem exactament aquestes nou fitxes i les remediem una a una: codi corregit, mapeig a requisits ASVS i reescaneig per verificar que el control funciona de veritat.

Curs d'OWASP: Directrius i Estàndards per a la Seguretat en Aplicacions Web

Mòdul 1: Introducció a OWASP

Mòdul 2: Principals Projectes d'OWASP

Mòdul 3: OWASP Top Ten 2021 en Profunditat

Mòdul 4: OWASP ASVS (Application Security Verification Standard)

Mòdul 5: OWASP SAMM (Software Assurance Maturity Model)

Mòdul 6: OWASP ZAP (Zed Attack Proxy)

Mòdul 7: Bones Pràctiques i Recomanacions

Mòdul 8: Exercicis Pràctics i Casos d'Estudi

Mòdul 9: Avaluació i Certificació

© Copyright 2026. Tots els drets reservats