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
- Objectiu i entorn del laboratori
- Metodologia: com abordar la identificació
- El checklist basat en Top Ten i ASVS
- El codi a revisar: endpoints, component i configuració
- Com documentar una troballa i registrar-la al backlog
- Errors comuns i consells
- Exercicis
- 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]
- 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.
- 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.
- 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.
- 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.
- Triatge. Descarta falsos positius amb evidència (reproduir la petició), no per intuïció.
- 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
- OWASP Top Ten
- OWASP ASVS (Application Security Verification Standard)
- OWASP SAMM (Software Assurance Maturity Model)
- OWASP ZAP (Zed Attack Proxy)
- Altres Projectes Clau: WSTG, Cheat Sheets i Dependency-Check
Mòdul 3: OWASP Top Ten 2021 en Profunditat
- A01:2021 – Pèrdua de Control d'Accés
- A02:2021 – Errors Criptogràfics i Exposició de Dades Sensibles
- A03:2021 – Injecció
- Cross-Site Scripting (XSS) en Profunditat
- A04:2021 – Disseny Insegur
- A05:2021 – Configuració de Seguretat Incorrecta
- Entitats Externes XML (XXE)
- A06:2021 – Components Vulnerables i Desactualitzats
- A07:2021 – Errors d'Identificació i Autenticació
- A08:2021 – Errors d'Integritat de Programari i Dades (Deserialització Insegura)
- A09:2021 – Errors de Registre i Monitorització
- A10:2021 – Server-Side Request Forgery (SSRF)
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)
- Introducció a ZAP
- Instal·lació i Configuració
- Escaneig de Vulnerabilitats
- Automatització de Proves de Seguretat
Mòdul 7: Bones Pràctiques i Recomanacions
- Cicle de Vida de Desenvolupament Segur (SDLC)
- Modelatge d'Amenaces (Threat Modeling)
- Integració de Seguretat en DevOps (DevSecOps)
- Formació i Conscienciació en Seguretat
- Eines i Recursos Addicionals
Mòdul 8: Exercicis Pràctics i Casos d'Estudi
- Exercici 1: Identificació de Vulnerabilitats
- Exercici 2: Implementació de Controls de Seguretat
- Cas d'Estudi 1: Anàlisi d'un Incident de Seguretat
- Cas d'Estudi 2: Millora de la Seguretat en una Aplicació Web
