Pots tenir un disseny sòlid (A04) i un codi sense injeccions (A03), i tot i així quedar exposat per com està configurat i desplegat el sistema. A05:2021 – Configuració de Seguretat Incorrecta (Security Misconfiguration) recull els errors que no són a la teva lògica, sinó als ajustos: valors per defecte insegurs, comptes i contrasenyes de fàbrica, missatges d'error que revelen de més, capçaleres de seguretat absents, serveis i ports innecessaris, permisos laxos. És una de les categories més freqüents, precisament perquè el programari modern té centenars d'opcions i moltes vénen "obertes per comoditat".

En el Top Ten 2021, aquesta categoria va absorbir l'antic XXE (XML External Entities), que no és més que un parser XML mal configurat. Aquí el mencionem com a part d'A05, però per la seva tècnica específica el desenvolupem a fons a la lliçó 03-07. A BazarNube revisarem la configuració de l'API Express i dels contenidors Docker, dos focus habituals de mala configuració.

Avís legal i ètic: els exemples són il·lustratius i amb dades fictícies. Practica només sobre sistemes propis o amb autorització explícita.

Contingut

  1. Què abasta la configuració incorrecta
  2. Capçaleres de seguretat absents a Express
  3. Missatges d'error verbosos i mode de desenvolupament en producció
  4. Comptes i valors per defecte; superfície innecessària
  5. Hardening de contenidors Docker
  6. XXE com a configuració de parser (remès a 03-07)
  7. Procés: hardening reproduïble i automatitzat
  8. Errors comuns, exercicis i solucions

  1. Què abasta la configuració incorrecta

Un cop d'ull a la varietat d'errors que cauen sota A05:

Àrea Error típic Risc
Capçaleres HTTP Falten HSTS, X-Content-Type-Options, CSP XSS, sniffing, clickjacking
Errors Stack traces al client Fuga d'informació interna
Comptes Usuari/clau per defecte sense canviar Accés trivial
Serveis Ports/panells d'administració exposats Superfície d'atac
Framework Mode debug actiu en producció Fuga de dades, execució
Parsers XML amb entitats externes habilitades XXE (03-07)
Permisos Fitxers/buckets amb accés públic Exposició de dades

El fil comú: valors per defecte pensats per a "que funcioni", no per a "que sigui segur", que mai es van endurir.

  1. Capçaleres de seguretat absents a Express

L'API de BazarNube va arrencar sense capçaleres de seguretat i, pitjor, revelant la seva tecnologia:

// app.js — VULNERABLE: sense capceleres de seguretat, revela X-Powered-By
const express = require('express');
const app = express();
// Express envia per defecte "X-Powered-By: Express" (pista per a l'atacant)
app.get('/', (req, res) => res.send('BazarNube API'));

Cada resposta anuncia X-Powered-By: Express (facilita a l'atacant buscar CVEs d'aquella pila) i no inclou cap capçalera defensiva. Correcció amb helmet, que fixa un conjunt de capçaleres sensates:

// app.js — SEGUR: helmet aplica capceleres de seguretat i amaga la tecnologia
const helmet = require('helmet');
app.disable('x-powered-by');            // deixa de revelar el framework
app.use(helmet());                       // HSTS, X-Content-Type-Options, etc.
app.use(helmet.contentSecurityPolicy({ directives: {
  defaultSrc: ["'self'"], scriptSrc: ["'self'"], frameAncestors: ["'none'"]
}}));
Capçalera Què fa Davant de
Strict-Transport-Security Força HTTPS Degradació TLS (veure A02)
X-Content-Type-Options: nosniff Impedeix endevinar el tipus MIME Atacs per sniffing
Content-Security-Policy Restringeix orígens de scripts/recursos XSS (veure 03-04)
X-Frame-Options/frame-ancestors Impedeix l'emmarcament Clickjacking
Referrer-Policy Limita el Referer enviat Fuga de URLs

  1. Missatges d'error verbosos i mode desenvolupament

En producció, un error ha de registrar el detall al servidor i retornar al client un missatge genèric. BazarNube tenia el contrari:

// VULNERABLE: envia el stack trace al client
app.use((err, req, res, next) => {
  res.status(500).send(err.stack);   // revela rutes, versions, estructura
});

Un stack trace exposa rutes de fitxers, versions de llibreries, noms de taules i de vegades fragments de consultes: un mapa per a l'atacant. Correcció:

// SEGUR: log intern detallat, resposta generica
app.use((err, req, res, next) => {
  logger.error({ err, path: req.path, reqId: req.id }); // detall NOMES al log
  res.status(500).json({ error: 'Error intern', reqId: req.id });
});

El reqId permet al suport correlacionar la incidència amb el log sense revelar res al client. Relacionat: desactiva el mode debug/development de frameworks en producció (NODE_ENV=production), que sovint activa pàgines d'error detallades i desactiva optimitzacions de seguretat.

  1. Comptes i valors per defecte; superfície innecessària

  • Comptes per defecte: panells d'administració, bases de dades i serveis solen portar admin/admin o similars. Canvia'ls sempre; deshabilita els que no facis servir.
  • Serveis i ports innecessaris: cada servei exposat és superfície d'atac. Si BazarNube no necessita exposar el port de PostgreSQL a l'exterior, no el publiquis.
  • Endpoints de diagnòstic: panells de mètriques, /debug, documentació d'API interna... han d'estar protegits o deshabilitats en producció.
  • Directoris i llistats: desactiva el directory listing i no serveixis fitxers de configuració (.env, .git).

  1. Hardening de contenidors Docker

BazarNube corre en Docker. Un Dockerfile descurat és configuració incorrecta de manual:

# Dockerfile — VULNERABLE
FROM node:latest                 # tag flotant: versio impredictible
WORKDIR /app
COPY . .                          # copia TOT, inclos .env i .git
RUN npm install
USER root                         # corre com a root (per defecte)
CMD ["node", "app.js"]

Problemes: imatge base amb tag flotant (latest, impossible de reproduir i sovint amb paquets de més), còpia de secrets i de l'historial Git a la imatge, i execució com a root (si algú s'escapa del procés, és root al contenidor). Versió endurida:

# Dockerfile — SEGUR
FROM node:20.17-slim             # versio fixada i variant slim (menys superficie)
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev            # instalacio reproduible, sense devDependencies
COPY src ./src                    # copiar nomes el necessari (veure .dockerignore)
RUN addgroup --system app && adduser --system --ingroup app app
USER app                          # executar com a usuari sense privilegis
CMD ["node", "src/app.js"]

I un .dockerignore per no filtrar secrets ni l'historial:

.git
.env
node_modules
*.log
Pràctica Per què
Tag de versió fixada Reproduïbilitat; evita canvis silenciosos
Variant slim/mínima Menys paquets = menys CVEs (enllaça amb A06, 03-08)
USER no root Limita l'impacte d'un escapament del procés
.dockerignore Evita copiar .env, .git, secrets
Escanejar la imatge Detecta vulnerabilitats en capes (SCA d'imatges)

  1. XXE com a configuració de parser

L'antic A04:2017 (XXE) va quedar absorbit dins d'A05 perquè, en el fons, és un parser XML mal configurat: ve per defecte amb el processament d'entitats externes activat, i ningú el va desactivar. En ser un tema amb tècnica i explotació pròpies (lectura de fitxers, SSRF, DoS per "billion laughs"), el desenvolupem complet a la lliçó 03-07 – Entitats Externes XML (XXE). Recorda la relació: XXE és un cas concret de configuració de seguretat incorrecta.

  1. Procés: hardening reproduïble

La configuració segura no és un ajust puntual, és un procés repetible:

flowchart LR
  A[Baseline de hardening] --> B[Config com a codi]
  B --> C[Escaneig automatic en CI]
  C --> D[Mateix entorn dev/staging/prod]
  D --> A
  • Baseline de hardening: una llista de referència (p. ex. CIS Benchmarks) de com ha de quedar cada component.
  • Configuració com a codi: defineix la config en fitxers versionats (Dockerfile, IaC), no a mà en cada servidor. Així és auditable i reproduïble.
  • Paritat d'entorns: dev, staging i producció s'han de configurar igual; moltes bretxes neixen d'un staging "obert".
  • Escaneig automàtic: eines que revisen capçaleres, config de contenidors i IaC en el pipeline (ho veurem amb ZAP a M6 per a la part web).

Errors Comuns i Consells

  • Desplegar amb la config per defecte. Gairebé sempre prioritza "que arrenqui" sobre "que sigui segur".
  • Revelar la tecnologia (X-Powered-By, capçaleres de versió, stack traces). Amaga-ho.
  • Deixar debug/development en producció. Fixa NODE_ENV=production i equivalents.
  • Contenidors com a root i amb tag latest. Fes servir un usuari sense privilegis i versions fixades.
  • Copiar .env/.git a la imatge. Fes servir .dockerignore.
  • Configurar a mà cada servidor. Deriva en inconsistències; fes servir configuració com a codi.
  • Consell: tracta la configuració amb el mateix rigor que el codi: versionada, revisada i escanejada en CI.

Exercicis

Exercici 1. Enumera tres problemes de seguretat en aquest fragment de desplegament i corregeix-los:

const app = express();
app.use(express.json());
app.use((err, req, res, next) => res.status(500).send(err.stack));
// sense helmet, NODE_ENV sense definir

Exercici 2. Un company diu: "amagar X-Powered-By no serveix, l'atacant trobarà la tecnologia igualment". Què li respondries?

Exercici 3. Explica per què executar el contenidor com a root agreuja l'impacte d'una altra vulnerabilitat (per exemple, una execució d'ordres com la d'A03).

Solucions

Solució 1. Problemes: (1) no hi ha capçaleres de seguretat → afegir helmet; (2) el handler d'error retorna el stack al client → registrar internament i respondre genèric; (3) NODE_ENV sense definir → fixar production. A més, amagar X-Powered-By. Vegeu les seccions 2 i 3.

Solució 2. És cert que un atacant determinat pot inferir la tecnologia per altres vies, però amagar-la apuja el cost i frena l'escaneig automatitzat que busca versions concretes per llançar exploits coneguts. És defensa en profunditat: no és la barrera principal, però suma i no costa res.

Solució 3. Si el procés corre com a root dins del contenidor i una vulnerabilitat permet executar ordres, aquestes ordres s'executen amb privilegis màxims: l'atacant pot modificar qualsevol fitxer del contenidor, instal·lar eines i augmentar la probabilitat d'escapar-se cap a l'amfitrió. Amb un usuari sense privilegis, el radi de dany es redueix notablement (mínim privilegi, defensa en profunditat).

Conclusió

A05 ens recorda que la seguretat no acaba en el codi: els valors per defecte, les capçaleres, els errors, els comptes i els contenidors s'han d'endurir de manera explícita, repetible i auditable. A BazarNube afegim helmet i amaguem la tecnologia, silenciem els stack traces al client, i endurim el Dockerfile (versió fixada, usuari no root, .dockerignore). La clau: configuració com a codi, igual de revisada que la lògica.

Entrada de backlog — A05: helmet + CSP activats i X-Powered-By desactivat; handler d'errors genèric amb reqId; NODE_ENV=production; Dockerfile endurit (tag fixat, USER app, .dockerignore); pendent escaneig de config en CI.

Vam mencionar que el XXE és un parser XML mal configurat. El mòdul legacy Java de BazarNube processa XML de facturació, així que és el moment d'obrir aquella caixa. La lliçó següent és Entitats Externes XML (XXE).

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