← Tutti gli episodi

Stagione 93  /  Episodio 10

La crepa e il confronto

CVE-2023-4863, la crepa nel decoder senza perdita di libwebp, e le sue lezioni; poi WebP accanto ad AVIF e JPEG XL nel 2026, con una guida per scegliere. Chiusura della stagione.

Note dell'episodio

Bentornati in bottega, per l'ultima volta in questa stagione. Ogni mosaicista prima o poi si trova davanti a una crepa. A volte è in superficie, una tessera che si stacca. A volte è sotto, nel letto di malta, invisibile finché il pannello non cede.

La crepa più grave nella storia di WebP non era nelle immagini. Era nell'attrezzo che tutti usavano per leggerle. E ci ha insegnato qualcosa che va molto oltre WebP.

All'inizio di settembre 2023, il gruppo di sicurezza di Apple e il Citizen Lab dell'Università di Toronto segnalano una vulnerabilità sfruttata attivamente. Faceva parte di una catena di attacco che il Citizen Lab chiama BLASTPASS: un'immagine malevola, inviata tramite iMessage, poteva compromettere un iPhone con l'allora ultima versione di iOS, la 16.6, senza che la vittima toccasse nulla. Secondo il Citizen Lab, la catena era usata per installare Pegasus, lo spyware del gruppo NSO.

Apple corregge il proprio framework di gestione delle immagini. Ma il difetto, si scopre, non era soltanto di Apple. Era in libwebp. Google rilascia d'urgenza un aggiornamento di Chrome e, subito dopo, la versione 1.3.2 di libwebp. La vulnerabilità prende il nome di CVE-2023-4863: un overflow nell'area di memoria dinamica, che permette di scrivere fuori dai limiti di un buffer attraverso un file WebP costruito apposta. Erano vulnerabili tutte le versioni dalla 0.5.0 alla 1.3.1, cioè anni e anni di software.

C'è anche un piccolo pasticcio burocratico che ne racconta la portata. Il CVE inizialmente descriveva il problema come un difetto di Chrome. Pochi giorni dopo ne viene creato un secondo, specifico per libwebp, che poi viene ritirato come duplicato. Nel frattempo molti scanner di sicurezza guardavano solo il nome del browser e non segnalavano le altre applicazioni colpite. Che erano tantissime.

Ricordate il quarto episodio? La compressione senza perdita, i codici di Huffman, le tabelle. È proprio lì.

Per decodificare velocemente i codici di Huffman, libwebp costruisce delle tabelle di consultazione. C'è una tabella principale, indicizzata dai primi otto bit, e per i codici più lunghi, che possono arrivare a quindici bit, ci sono tabelle secondarie. La memoria per tutte queste tabelle veniva allocata in anticipo, con una dimensione precalcolata che bastava per qualunque codice valido.

Il punto debole è in quella parola: valido. Un file costruito apposta poteva descrivere codici che non erano un insieme di Huffman corretto, in un modo che faceva crescere le tabelle secondarie oltre la dimensione prevista. E il programma, costruendole, scriveva oltre la fine del buffer. Dati scelti dall'attaccante, scritti in memoria dove non dovevano stare: il punto di partenza ideale per prendere il controllo del processo.

La correzione, in sostanza, verifica la validità dei codici prima di costruire le tabelle e gestisce la memoria in modo da non poter più sforare.

Il difetto in sé è il tipo di errore che si trova, prima o poi, in qualunque codice C che fa parsing di dati complessi. Quello che l'ha reso così grave è la diffusione di libwebp.

Era dentro Chrome, Firefox, Edge, Safari attraverso il framework di Apple, Thunderbird. Ma era anche dentro tutte le applicazioni Electron, che si portano dietro una copia di Chromium: client di chat, editor di codice, strumenti di produttività. Dentro le librerie di elaborazione immagini di quasi ogni linguaggio, spesso nella forma di pacchetti precompilati che includono la propria copia di libwebp. Dentro le immagini Docker di mezzo mondo.

E qui sta la lezione. Aggiornare il sistema operativo non bastava. Ogni applicazione che includeva la propria copia della libreria andava aggiornata separatamente. Molti scoprirono in quei giorni di non sapere nemmeno quali componenti delle loro applicazioni contenessero libwebp.

Tre lezioni concrete, per chi scrive software.

La prima: sapere cosa c'è dentro. Un inventario dei componenti software, quello che oggi si chiama SBOM, vi permette di rispondere in pochi minuti alla domanda "usiamo questa libreria, e in che versione?". Senza, la risposta richiede giorni.

La seconda: i decodificatori di immagini sono superficie di attacco. Ogni volta che la vostra applicazione apre un file che arriva dall'esterno, che sia un upload, un allegato o un'immagine remota, sta eseguendo un parser complesso su dati scelti da qualcun altro. Le regole dell'episodio scorso, controllare prima di aprire, isolare i worker, limitare memoria e tempo, servono proprio a questo: se il parser cede, il danno resta confinato.

La terza: la sicurezza della memoria. Non è un caso che, quando nel 2026 Chrome ha deciso di supportare JPEG XL, lo abbia fatto con un decoder riscritto in Rust. La memoria gestita in modo sicuro elimina alla radice proprio la classe di errori di CVE-2023-4863.

Passiamo al confronto, perché la bottega di WebP non è più sola.

AVIF nasce intorno al 2019, prendendo i fotogrammi chiave del codec video AV1, esattamente come WebP aveva fatto con VP8. È supportato da Chrome dal 2020, da Firefox dal 2021, da Safari dal 2022. Rispetto a WebP comprime meglio, soprattutto a qualità medie e basse, e supporta dieci e dodici bit, l'HDR, il colore senza sottocampionamento. In cambio, la codifica è molto più lenta, e a qualità molto alte il vantaggio si riduce.

JPEG XL è lo standard ISO più recente. Comprime molto bene, supporta HDR e profondità elevate, decodifica in modo progressivo, e ha una caratteristica unica: può ricomprimere un JPEG esistente senza perdita, risparmiando circa il venti per cento e potendo tornare al JPEG originale bit per bit. La sua storia nei browser è stata travagliata: Chrome lo aveva aggiunto in via sperimentale, dietro un'opzione, e alla fine del 2022 aveva deciso di rimuoverlo. Safari lo supporta dalla versione 17, del 2023. E a ottobre 2026 Chrome lo ha abilitato con la versione 155, usando proprio il decoder in Rust di cui parlavamo. Per Firefox, conviene verificare lo stato al momento in cui ascoltate.

No. E qui provo a darvi una risposta onesta, non da tifoso.

WebP ha ancora quattro carte molto forti. Il supporto: è universale nei browser da anni, e molto ampio fuori dai browser, nelle librerie, nei CMS, nelle CDN, negli strumenti di grafica. La velocità: si codifica e si decodifica in fretta, il che conta quando convertite migliaia di immagini o le generate al volo. La compressione senza perdita: per grafica, icone e screenshot è ancora eccellente. E l'animazione con trasparenza: per sticker e piccole animazioni di interfaccia è la soluzione più pratica.

Dove invece perde? Sulle fotografie di qualità alta, dove AVIF e JPEG XL fanno meglio. Sull'HDR e sulle immagini con più di otto bit, dove semplicemente non può competere. Sui gradienti delicati, dove gli otto bit e il sottocampionamento mostrano i loro limiti.

Ecco una guida che potete usare domani.

Se volete una sola versione per immagine, semplice e compatibile con tutto: WebP. È la scelta di default più sensata per la maggior parte dei siti.

Se le immagini sono il cuore del sito, un portfolio, un e-commerce con foto grandi, una testata giornalistica: offrite AVIF o JPEG XL come prima scelta con l'elemento picture, e WebP come riserva. Il costo è un po' di complessità e tempi di codifica più lunghi.

Se avete un archivio enorme di JPEG da non toccare: JPEG XL con la ricompressione senza perdita è l'unica opzione che vi fa risparmiare spazio senza ricomprimere nulla.

Per grafica, icone e screenshot: WebP senza perdita o quasi senza perdita, oppure SVG quando l'immagine è vettoriale in origine. Non dimenticate che il formato migliore per un logo spesso non è un formato raster.

Per animazioni brevi con trasparenza: WebP animato. Per clip veri: un elemento video.

E per email e anteprime social: ancora JPEG e PNG.

E così chiudiamo la bottega. Siamo partiti da un problema del 2010, troppi byte e tre formati che sapevano fare una cosa sola. Abbiamo visto le tessere prese in prestito da un codec video, la cornice RIFF, il disegno a mano libera della compressione con perdita, la tessera esatta della compressione senza perdita, il vetro della trasparenza, il mosaico che si muove. Abbiamo aperto la cassetta degli attrezzi, esposto il mosaico sul web, costruito una catena di produzione, e oggi abbiamo guardato una crepa e i nuovi colleghi di bottega.

Se c'è una cosa che vorrei vi portaste via da questa stagione, è questa: un formato di immagine non è una scatola nera. È fatto di scelte, e ogni parametro che passate a un encoder corrisponde a una di quelle scelte. Conoscerle vi permette di decidere, invece di copiare valori da un tutorial.

Grazie per essere stati in bottega con me. Ci sentiamo nella prossima stagione.