Lo scripting cross-site basato su DOM (DOM XSS) si verifica quando i dati di un
elemento controllato dall'utente (ad esempio un nome utente o un URL di reindirizzamento ricavato dal frammento URL) raggiungono un destinatario, ovvero una funzione come eval()
o un settatore di proprietà come .innerHTML
che può eseguire codice JavaScript arbitrario.
L'XSS DOM è una delle vulnerabilità di sicurezza web più comuni ed è normale che i team di sviluppo la introducano accidentalmente nelle loro app. I Tipi attendibili forniscono gli strumenti per scrivere, controllare la sicurezza e mantenere le applicazioni libere dalle vulnerabilità DOM XSS rendendo sicure per impostazione predefinita le funzioni API web pericolose. I tipi di attendibilità sono disponibili come polyfill per i browser che non li supportano ancora.
Sfondo
Per molti anni, DOM XSS è stato una delle vulnerabilità di sicurezza web più diffuse e pericolose.
Esistono due tipi di cross-site scripting (XSS). Alcune vulnerabilità XSS sono causate da codice lato server che crea in modo non sicuro il codice HTML che forma il sito web. Altre hanno una causa principale sul client, dove il codice JavaScript chiama funzioni pericolose con contenuti controllati dall'utente.
Per evitare gli attacchi XSS lato server, non generare HTML concatenando stringhe. Utilizza invece librerie di modelli con estrazione automatica contestuale sicura, insieme a un criterio Content Security basato su nonce per una mitigazione aggiuntiva dei bug.
Ora i browser possono anche contribuire a impedire gli attacchi XSS basati su DOM lato client utilizzando Tipi attendibili.
Introduzione all'API
I tipi attendibili bloccano le seguenti funzioni sink rischiose. Potresti già riconoscerne alcune, perché i fornitori di browser e i framework web ti sconsigliano già di utilizzare queste funzionalità per motivi di sicurezza.
- Manipolazione dello script:
<script src>
e impostazione dei contenuti di testo degli elementi<script>
. - Generare HTML da una stringa:
- Esecuzione dei contenuti del plug-in:
- Compilazione di codice JavaScript di runtime:
eval
setTimeout
setInterval
new Function()
I tipi di attendibilità richiedono di elaborare i dati prima di trasmetterli a queste funzioni sink. L'utilizzo di una sola stringa non va a buon fine perché il browser non sa se i dati sono attendibili:
anElement.innerHTML = location.href;
Per indicare che i dati sono stati elaborati in modo sicuro, crea un oggetto speciale: Trusted Type.
anElement.innerHTML = aTrustedHTML;
Trusted Types riduce notevolmente la superficie di attacco DOM XSS della tua applicazione. Semplifica le revisioni di sicurezza e ti consente di applicare i controlli di sicurezza basati sui tipi eseguiti durante la compilazione, il linting o il bundling del codice in fase di esecuzione nel browser.
Come utilizzare i tipi di attendibilità
Prepararsi ai report sulle violazioni dei criteri di sicurezza del contenuto
Puoi implementare un raccoglitore di report, ad esempio reporting-api-processor o go-csp-collector open source, oppure utilizzare uno degli equivalenti commerciali. Puoi anche aggiungere log personalizzati e violazioni di debug nel browser utilizzando un ReportingObserver:
const observer = new ReportingObserver((reports, observer) => {
for (const report of reports) {
if (report.type !== 'csp-violation' ||
report.body.effectiveDirective !== 'require-trusted-types-for') {
continue;
}
const violation = report.body;
console.log('Trusted Types Violation:', violation);
// ... (rest of your logging and reporting logic)
}
}, { buffered: true });
observer.observe();
oppure aggiungendo un gestore di eventi:
document.addEventListener('securitypolicyviolation',
console.error.bind(console));
Aggiungi un'intestazione CSP solo per i report
Aggiungi la seguente intestazione della risposta HTTP ai documenti di cui vuoi eseguire la migrazione a Tipi attendibili:
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Ora tutte le violazioni vengono segnalate a //my-csp-endpoint.example
, ma il sito web continua a funzionare. La sezione successiva spiega come funziona
//my-csp-endpoint.example
.
Identifica le violazioni dei tipi di attendibilità
D'ora in poi, ogni volta che Trusted Types rileva una violazione, il browser invia un report a un report-uri
configurato. Ad esempio, quando l'applicazione
passa una stringa a innerHTML
, il browser invia il seguente report:
{
"csp-report": {
"document-uri": "https://my.url.example",
"violated-directive": "require-trusted-types-for",
"disposition": "report",
"blocked-uri": "trusted-types-sink",
"line-number": 39,
"column-number": 12,
"source-file": "https://my.url.example/script.js",
"status-code": 0,
"script-sample": "Element innerHTML <img src=x"
}
}
Questo indica che nella riga 39 di https://my.url.example/script.js
, innerHTML
è stato
chiamato con la stringa che inizia con <img src=x
. Queste informazioni dovrebbero aiutarti a restringere le parti di codice che potrebbero introdurre XSS DOM e che devono essere modificate.
Correggere le violazioni
Esistono un paio di opzioni per correggere una violazione di Trusted Type. Puoi rimuovere il codice in questione, utilizzare una libreria, creare un criterio di tipo attendibile o, come ultima soluzione, creare un criterio predefinito.
Riscrivere il codice in questione
È possibile che il codice non conforme non sia più necessario o che possa essere riscritto senza le funzioni che causano le violazioni:
el.textContent = ''; const img = document.createElement('img'); img.src = 'xyz.jpg'; el.appendChild(img);
el.innerHTML = '<img src=xyz.jpg>';
Utilizzare una libreria
Alcune librerie generano già tipi attendibili che puoi passare alle funzioni di destinazione. Ad esempio, puoi utilizzare DOMPurify per purificare uno snippet HTML, rimuovendo i payload XSS.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(html, {RETURN_TRUSTED_TYPE: true});
DOMPurify supporta i tipi attendibili
e restituisce HTML sanificato racchiuso in un oggetto TrustedHTML
in modo che il browser
non generi una violazione.
Crea un criterio di tipo Attendibile
A volte non puoi rimuovere il codice che causa la violazione e non esiste una libreria per convalidare il valore e creare un tipo attendibile. In questi casi, puoi creare autonomamente un oggetto Trusted Type.
Innanzitutto, crea una norma. I criteri sono fabbriche per Trusted Types che applicano determinate regole di sicurezza ai loro input:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
const escapeHTMLPolicy = trustedTypes.createPolicy('myEscapePolicy', {
createHTML: string => string.replace(/\</g, '<')
});
}
Questo codice crea un criterio chiamato myEscapePolicy
in grado di produrre oggetti
TrustedHTML
utilizzando la sua funzione createHTML()
. Le regole definite eseguono la codifica HTML dei caratteri <
per impedire la creazione di nuovi elementi HTML.
Utilizza il criterio nel seguente modo:
const escaped = escapeHTMLPolicy.createHTML('<img src=x onerror=alert(1)>');
console.log(escaped instanceof TrustedHTML); // true
el.innerHTML = escaped; // '<img src=x onerror=alert(1)>'
Utilizza un criterio predefinito
A volte non puoi modificare il codice in questione, ad esempio se carichi una biblioteca di terze parti da una CDN. In questo caso, utilizza un criterio predefinito:
if (window.trustedTypes && trustedTypes.createPolicy) { // Feature testing
trustedTypes.createPolicy('default', {
createHTML: (string, sink) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});
}
Il criterio denominato default
viene utilizzato ovunque venga utilizzata una stringa in un sink che accetta solo il tipo attendibile.
Passare all'applicazione dei criteri di sicurezza del contenuto
Quando l'applicazione non genera più violazioni, puoi iniziare a applicare i tipi attendibili:
Content-Security-Policy: require-trusted-types-for 'script'; report-uri //my-csp-endpoint.example
Ora, indipendentemente dalla complessità dell'applicazione web, l'unica cosa che può introdurre una vulnerabilità XSS DOM è il codice di uno dei tuoi criteri e puoi bloccare ulteriormente questo problema limitando la creazione dei criteri.