A08:2021 – Errors d'Integritat de Programari i Dades (Software and Data Integrity Failures) és una altra categoria reorganitzada el 2021: neix d'assumir que moltes bretxes es produeixen perquè el programari confia en dades o en codi sense verificar-ne la integritat. Aquí hi caben tres coses relacionades: la deserialització insegura (que el 2017 era una categoria pròpia i ara viu dins d'A08), la manca de verificació d'integritat en actualitzacions i pipelines de CI/CD, i l'ús de dades o dependències sense comprovar-ne la procedència.

El fil comú és la confiança no verificada. Si el mòdul Java de BazarNube deserialitza un objecte que ha vingut de fora sense comprovar res, pot acabar executant codi de l'atacant. Si el pipeline desplega un artefacte sense verificar-ne la signatura, pot desplegar-ne un de manipulat. En aquesta lliçó ataquem tots dos fronts: la deserialització al legacy Java i un pipeline sense verificació d'integritat.

Avís legal i ètic: els exemples d'explotació són il·lustratius i amb dades fictícies. Practica només sobre sistemes propis o amb autorització explícita. La deserialització insegura pot derivar en execució remota de codi: tracta-la amb extrema cura i només en entorns controlats.

Contingut

  1. Què és un error d'integritat
  2. Deserialització insegura: el cas del mòdul Java
  3. Com s'explota una deserialització (il·lustratiu)
  4. Prevenció de la deserialització insegura
  5. Integritat d'actualitzacions i del pipeline CI/CD
  6. Dependències i dades sense verificar
  7. Errors comuns, exercicis i solucions

  1. Què és un error d'integritat

La integritat garanteix que una dada o un artefacte no ha estat alterat i prové de qui diu provenir. Un error d'integritat es produeix quan el sistema actua sobre alguna cosa sense comprovar-la: deserialitza un objecte arbitrari, instal·la una actualització sense signatura, executa un script descarregat sense verificar-ne el hash. La defensa transversal és verificar abans de confiar: signatures digitals, hashes, canals autenticats.

  1. Deserialització insegura: el cas del mòdul Java

Serialitzar és convertir un objecte en bytes per guardar-lo o transmetre'l; deserialitzar és el procés invers. El perill apareix quan deserialitzes dades controlades per l'atacant amb un mecanisme que pot instanciar classes i executar lògica durant el procés. La serialització nativa de Java és l'exemple clàssic.

El mòdul legacy de BazarNube guarda l'estat del carretó en una cookie serialitzada amb Java, "per no tocar la base de dades":

// CartController.java (modul legacy) — VULNERABLE a deserialitzacio insegura
public Cart loadCart(String cookieValue) throws Exception {
    byte[] data = Base64.getDecoder().decode(cookieValue);
    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
    return (Cart) ois.readObject();   // deserialitza el que vingui a la cookie
}

El problema: ObjectInputStream.readObject() sobre dades del client. La cookie la controla l'usuari; pot substituir el carretó serialitzat per un objecte maliciós que aprofiti una "gadget chain" (una cadena de classes presents al classpath el procés de deserialització de les quals desemboca en execució d'ordres).

  1. Com s'explota (il·lustratiu)

L'atacant no envia un Cart; envia un objecte serialitzat especialment construït amb eines conegudes (del tipus que generen cadenes de gadgets a partir de llibreries comunes del classpath). En cridar readObject(), la deserialització recorre aquella cadena i, com a efecte col·lateral, executa una ordre al servidor —per exemple, obrir una connexió inversa o llegir fitxers. No cal encertar cap contrasenya: n'hi ha prou amb que l'endpoint deserialitzi dades no fiables i que al classpath existeixi una cadena explotable.

flowchart LR
  A[Atacant crea objecte serialitzat malicios] --> B[L'envia a la cookie del carreto]
  B --> C[readObject al servidor]
  C --> D[Gadget chain del classpath]
  D --> E[Execucio d'ordres al servidor]

És de les vulnerabilitats més severes: sol significar execució remota de codi.

  1. Prevenció de la deserialització insegura

La regla d'or: no deserialitzis dades no fiables amb mecanismes que puguin instanciar objectes arbitraris. En ordre de preferència:

  1. No serialitzis objectes al client. Guarda només un identificador i recupera l'estat del servidor. El carretó ha de viure a la base de dades, referenciat per un id de sessió.
  2. Fes servir formats de dades, no d'objectes. JSON amb un parser que no instancii tipus arbitraris (sense polymorphic type handling activat). Deserialitza a una estructura coneguda i valida.
  3. Si és imprescindible la serialització binària, aplica allowlist de classes permeses (ObjectInputFilter en Java) i verifica la integritat de la dada amb una signatura/HMAC.

Correcció: estat al servidor + JSON validat

// CartController.java — SEGUR: la cookie nomes porta un id opac
public Cart loadCart(String sessionId) {
    // L'estat real viu a la base de dades, no al client
    return cartRepository.findBySession(sessionId)
        .orElseGet(Cart::new);
}

I si en algun flux calgués acceptar JSON del client, deserialitzar a un tipus concret sense habilitar el maneig polimòrfic de tipus:

// JSON segur: mapatge a un tipus conegut, sense default typing
ObjectMapper mapper = new ObjectMapper();
// NO habilitar activateDefaultTyping(): aixo reintroduiria el risc de gadgets
CartDto dto = mapper.readValue(json, CartDto.class);
validate(dto);

Com a reforç (defensa en profunditat) per a dades que hagin d'anar i tornar del client, signa'n la integritat:

// HMAC per detectar manipulacio d'una dada que viatja al client
String payload = base64(json);
String mac = hmacSha256(SECRET, payload);   // clau des del gestor de secrets
// En rebre: recomputar l'HMAC i comparar en temps constant abans de fer servir la dada
Enfocament Seguretat
ObjectInputStream sobre dades del client Molt perillós (RCE)
JSON amb default typing activat Perillós (gadgets)
JSON a tipus concret + validació Segur
Estat al servidor, només id al client Segur (recomanat)
Dada signada (HMAC/signatura) + validació Segur per a dades que han de viatjar

  1. Integritat d'actualitzacions i del pipeline CI/CD

La integritat no acaba en la deserialització. El pipeline que construeix i desplega BazarNube és un objectiu d'alt valor: si un atacant injecta codi en el procés de build o substitueix un artefacte, compromet tots els usuaris d'un sol cop (atac a la cadena de subministrament).

El pipeline de BazarNube tenia descuits típics:

# pipeline VULNERABLE (resum)
steps:
  - run: curl -s https://example.test/install.sh | bash   # executa script sense verificar
  - run: docker pull miregistre/app:latest                 # tag mutable, sense signatura
  - deploy: kubectl apply -f k8s/                          # sense verificar l'artefacte

Problemes: executar un script descarregat sense verificar-ne el hash, fer servir imatges amb tag mutable (latest, que pot canviar sota els teus peus) i desplegar artefactes sense verificar-ne la signatura. Versió amb controls d'integritat:

# pipeline SEGUR (resum)
steps:
  - run: |
      curl -s -o install.sh https://example.test/install.sh
      echo "<hash_esperat>  install.sh" | sha256sum -c -   # verifica integritat
      bash install.sh
  - run: docker pull miregistre/app@sha256:<digest>          # imatge per digest immutable
  - run: cosign verify miregistre/app@sha256:<digest>        # verifica la signatura de l'artefacte
  - deploy: kubectl apply -f k8s/

Controls clau d'integritat en CI/CD:

  • Fixar artefactes per digest immutable, no per tags mutables.
  • Signar i verificar artefactes i imatges (signatura d'artefactes, provenance del build).
  • Verificar hashes de tot el que es descarregui al pipeline.
  • Protegir el pipeline com a codi sensible: mínims permisos, secrets gestionats, revisió de canvis en la mateixa definició del pipeline.

  1. Dependències i dades sense verificar

A08 se solapa amb A06 (components) en la part de procedència: instal·lar dependències sense verificar-ne la integritat (ignorar els hashes del lockfile, fer servir registres no fiables) és un error d'integritat. Assegura't de:

  • Respectar els hashes d'integritat dels lockfiles (package-lock.json, pom.xml amb checksums).
  • Instal·lar des de registres controlats (proxy/registre intern) i no des de fonts arbitràries.
  • Verificar la signatura d'artefactes crítics quan estigui disponible.

Errors Comuns i Consells

  • Deserialitzar dades del client amb ObjectInputStream. Evita-ho; guarda l'estat al servidor.
  • Activar el default typing de JSON. Reintrodueix el risc de gadgets; deserialitza a tipus concrets.
  • Confiar en tags mutables (latest). Fes servir digests immutables i signatures.
  • Descarregar i executar scripts sense verificar el hash. Verifica sempre la integritat del que descarregues.
  • Tractar el pipeline com una cosa no crítica. És un objectiu de cadena de subministrament; protegeix-lo.
  • Ignorar els hashes dels lockfiles. Són la teva verificació d'integritat de dependències.
  • Consell: aplica "verificar abans de confiar" a tota dada o artefacte que creui un límit: objectes, actualitzacions, imatges, dependències.

Exercicis

Exercici 1. Per què guardar el carretó com a objecte Java serialitzat en una cookie és perillós, i com ho redissenyaries per eliminar la classe de vulnerabilitat?

Exercici 2. Un pipeline fa docker pull miregistre/app:latest i desplega. Enumera dos problemes d'integritat i la seva correcció.

Exercici 3. Un company proposa "solucionar" la deserialització xifrant la cookie amb AES. Elimina el risc de deserialització insegura? Matisa.

Solucions

Solució 1. És perillós perquè readObject() sobre dades que l'usuari controla pot instanciar una gadget chain del classpath i derivar en execució d'ordres (RCE). Redisseny: no serialitzar objectes al client; guardar l'estat del carretó a la base de dades i enviar al client només un identificador opac de sessió. Així el servidor mai deserialitza dades no fiables.

Solució 2. (1) Tag mutable latest: el contingut pot canviar sense que ho sàpigues → fer servir @sha256:<digest> immutable. (2) Sense verificació de signatura: podrien haver substituït la imatge → signar en el build i verificar (cosign verify) abans de desplegar. A més, restringir el registre d'origen.

Solució 3. Ajuda però no elimina la classe per si sola. Xifrar/signar amb una clau secreta evita que un atacant extern fabriqui la cookie (si la clau està ben protegida), i és una defensa vàlida (integritat/confidencialitat). Però si la clau es filtra, o el flux accepta dades serialitzades per altres vies, el risc de RCE per deserialització persisteix. La solució de fons continua sent no deserialitzar objectes no fiables: signar és defensa en profunditat, no substitut del redisseny.

Conclusió

A08 ens ensenya a no confiar sense verificar. A BazarNube vam eliminar la deserialització insegura del carretó portant l'estat al servidor i fent servir JSON mapejat a tipus concrets, i vam endurir el pipeline amb artefactes per digest, signatures verificades i hashes de tot el descarregat. El principi "verificar abans de confiar" cobreix objectes, actualitzacions, imatges i dependències.

Entrada de backlog — A08: carretó redissenyat (estat a la BD, només id al client); prohibit ObjectInputStream sobre dades externes i el default typing de JSON; pipeline amb imatges per digest, cosign verify i verificació de hashes; respecte dels hashes de lockfiles.

Hem previngut moltes coses. Però cap prevenció és perfecta: quan alguna cosa passi, necessitem veure-la. La lliçó següent aborda A09:2021 – Errors de Registre i Monitorització, amb el logging de l'API de BazarNube i el seu enllaç amb el cas d'incident del mòdul 8.

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