In questa sezione, descriveremo alcuni principi generali per prevenire le vulnerabilità di cross-site scripting e le modalità di utilizzo di varie tecnologie comuni per la protezione dagli attacchi XSS.

La prevenzione cross-site scripting può generalmente essere ottenuta tramite due livelli di difesa:

  • Codifica i dati in uscita
  • Convalida l’ingresso all’arrivo

È possibile utilizzare Burp Scanner per eseguire la scansione dei siti web per numerose vulnerabilità di sicurezza tra cui XSS. La logica di scansione all’avanguardia di Burp replica le azioni di un attaccante esperto ed è in grado di ottenere una copertura corrispondentemente elevata delle vulnerabilità XSS. È possibile utilizzare Burp Scanner per ottenere la certezza che le difese contro gli attacchi XSS stanno lavorando in modo efficace.

Codifica i dati sull’output

La codifica deve essere applicata direttamente prima che i dati controllabili dall’utente vengano scritti in una pagina, poiché il contesto in cui si sta scrivendo determina il tipo di codifica che è necessario utilizzare. Ad esempio, i valori all’interno di una stringa JavaScript richiedono un tipo diverso di escape rispetto a quelli in un contesto HTML.

In HTML In un contesto, si dovrebbe convertire i non-white list valori in entità HTML:

  • < converte: &lt;
  • > converte: &gt;

In una stringa JavaScript contesto, camere non-valori alfanumerici devono essere Unicode sfuggito:

  • < converte: \u003c
  • > converte: \u003e

a Volte è necessario applicare più strati di codifica, nell’ordine corretto. Ad esempio, per incorporare in modo sicuro l’input dell’utente all’interno di un gestore di eventi, è necessario gestire sia il contesto JavaScript che il contesto HTML. Quindi è necessario prima Unicode-escape l’input, e quindi HTML-codificarlo:

<a href="#" onclick="x='This string needs two layers of escaping'">test</a>

Validate input on arrival

La codifica è probabilmente la linea più importante della difesa XSS, ma non è sufficiente per prevenire le vulnerabilità XSS in ogni contesto. Dovresti anche convalidare l’input nel modo più rigoroso possibile nel momento in cui viene ricevuto per la prima volta da un utente.

Esempi di convalida dell’input includono:

  • Se un utente invia un URL che verrà restituito nelle risposte, convalidando che inizia con un protocollo sicuro come HTTP e HTTPS. Altrimenti qualcuno potrebbe sfruttare il tuo sito con un protocollo dannoso come javascript o data.
  • Se un utente fornisce un valore che dovrebbe essere numerico, convalidando che il valore contiene effettivamente un numero intero.
  • La convalida di tale input contiene solo un set di caratteri previsto.

La convalida dell’input dovrebbe idealmente funzionare bloccando l’input non valido. Un approccio alternativo, di tentare di pulire l’input non valido per renderlo valido, è più soggetto a errori e dovrebbe essere evitato ove possibile.

Whitelist vs blacklisting

La convalida dell’input dovrebbe generalmente impiegare whitelist piuttosto che blacklist. Ad esempio, invece di provare a creare un elenco di tutti i protocolli dannosi (javascript, data, ecc.), semplicemente fare una lista di protocolli sicuri (HTTP, HTTPS) e non consentire nulla che non sia nella lista. Ciò garantirà che la tua difesa non si rompa quando compaiono nuovi protocolli dannosi e la renderà meno suscettibile agli attacchi che cercano di offuscare valori non validi per eludere una lista nera.

Consentire l’HTML “sicuro”

Consentire agli utenti di pubblicare il markup HTML dovrebbe essere evitato laddove possibile, ma a volte è un requisito aziendale. Ad esempio, un sito di blog potrebbe consentire la pubblicazione di commenti contenenti un markup HTML limitato.

L’approccio classico consiste nel cercare di filtrare tag e JavaScript potenzialmente dannosi. Puoi provare a implementarlo usando una whitelist di tag e attributi sicuri, ma grazie alle discrepanze nei motori di analisi del browser e alle stranezze come mutation XSS, questo approccio è estremamente difficile da implementare in modo sicuro.

L’opzione meno cattiva è quella di utilizzare una libreria JavaScript che esegue il filtraggio e la codifica nel browser dell’utente, come DOMPurify. Altre librerie consentono agli utenti di fornire contenuti in formato markdown e convertire il markdown in HTML. Sfortunatamente, tutte queste librerie hanno vulnerabilità XSS di volta in volta, quindi questa non è una soluzione perfetta. Se si utilizza uno si dovrebbe monitorare attentamente per gli aggiornamenti di sicurezza.

Nota

Oltre a JavaScript, altri contenuti come CSS e persino HTML regolari possono essere dannosi in alcune situazioni.

Attacchi che utilizzano CSS dannosi

Come prevenire XSS utilizzando un motore di template

Molti siti web moderni utilizzano motori di template lato server come Twig e Freemarker per incorporare contenuti dinamici in HTML. Questi in genere definiscono il proprio sistema di escape. Ad esempio, in Twig, è possibile utilizzare il filtro e() , con un argomento che definisce il contesto:

{{ user.firstname | e('html') }}

Alcuni altri motori di template, come Jinja e React, sfuggono al contenuto dinamico per impostazione predefinita che impedisce efficacemente la maggior parte delle occorrenze di XSS.

Si consiglia di esaminare attentamente le funzionalità di escape quando si valuta se utilizzare un determinato motore di template o framework.

Nota

Se concatenate direttamente l’input dell’utente nelle stringhe del modello, sarete vulnerabili all’iniezione del modello lato server che è spesso più grave di XSS.

Come prevenire XSS in PHP

In PHP esiste una funzione integrata per codificare entità chiamata htmlentities. Dovresti chiamare questa funzione per sfuggire al tuo input quando si trova all’interno di un contesto HTML. La funzione dovrebbe essere chiamata con tre argomenti:

  • La tua stringa di input.
  • ENT_QUOTES, che è un flag che specifica che tutte le virgolette dovrebbero essere codificate.
  • Il set di caratteri, che nella maggior parte dei casi dovrebbe essere UTF-8.

Per esempio:

<?php echo htmlentities($input, ENT_QUOTES, 'UTF-8');?>

Quando in un contesto stringa JavaScript, è necessario Unicode-escape input come già descritto. Sfortunatamente, PHP non fornisce un’API per Unicode-escape una stringa. Ecco del codice per farlo in PHP:

<?php

function jsEscape($str) {
$output = '';
$str = str_split($str);
for($i=0;$i<count($str);$i++) {
$chrNum = ord($str);
$chr = $str;
if($chrNum === 226) {
if(isset($str) && ord($str) === 128) {
if(isset($str) && ord($str) === 168) {
$output .= '\u2028';
$i += 2;
continue;
}
if(isset($str) && ord($str) === 169) {
$output .= '\u2029';
$i += 2;
continue;
}
}
}
switch($chr) {
case "'":
case '"':
case "\n";
case "\r";
case "&";
case "\";
case "<":
case ">":
$output .= sprintf("\u%04x", $chrNum);
break;
default:
$output .= $str;
break;
}
}
return $output;
}
?>

Ecco come usare la funzione jsEscape in PHP:

<script>x = '<?php echo jsEscape($_GET)?>';</script>

In alternativa, è possibile utilizzare un motore di template.

Come prevenire XSS lato client in JavaScript

Per sfuggire all’input dell’utente in un contesto HTML in JavaScript, è necessario il proprio codificatore HTML perché JavaScript non fornisce un’API per codificare HTML. Ecco alcuni esempi di codice JavaScript che converte una stringa in entità HTML:

function htmlEncode(str){
return String(str).replace(//gi, function(c){
return '&#'+c.charCodeAt(0)+';';
});
}

Si dovrebbe quindi utilizzare questa funzione come segue:

<script>document.body.innerHTML = htmlEncode(untrustedValue)</script>

Se il tuo input è all’interno di una stringa JavaScript, hai bisogno di un encoder che esegua l’escape Unicode. Ecco un esempio Unicode-encoder:

function jsEscape(str){
return String(str).replace(//gi, function(c){
return '\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4);
});

}

Si dovrebbe quindi utilizzare questa funzione come segue:

<script>document.write('<script>x="'+jsEscape(untrustedValue)+'";<\/script>')</script>

Come prevenire XSS in jQuery

La forma più comune di XSS in jQuery è quando si passa l’input dell’utente a un selettore jQuery. Gli sviluppatori Web userebbero spesso location.hash e lo passerebbero al selettore che causerebbe XSS poiché jQuery renderebbe l’HTML. jQuery ha riconosciuto questo problema e ha patchato la logica del selettore per verificare se l’input inizia con un hash. Ora jQuery eseguirà il rendering HTML solo se il primo carattere è <. Se si passano dati non attendibili al selettore jQuery, assicurarsi di sfuggire correttamente al valore utilizzando la funzione jsEscape sopra.

Mitigare XSS utilizzando Content Security policy (CSP)

Content security policy (CSP) è l’ultima linea di difesa contro lo scripting cross-site. Se la prevenzione XSS non riesce, è possibile utilizzare CSP per mitigare XSS limitando ciò che un utente malintenzionato può fare.

CSP consente di controllare varie cose, ad esempio se gli script esterni possono essere caricati e se gli script inline verranno eseguiti. Per distribuire CSP è necessario includere un’intestazione di risposta HTTP denominata Content-Security-Policy con un valore contenente il criterio.

Un CSP di esempio è il seguente:

default-src 'self'; script-src 'self'; object-src 'none'; frame-src 'none'; base-uri 'none';

Questo criterio specifica che risorse come immagini e script possono essere caricate solo dalla stessa origine della pagina principale. Quindi, anche se un utente malintenzionato può iniettare con successo un payload XSS, può caricare solo risorse dall’origine corrente. Ciò riduce notevolmente la possibilità che un utente malintenzionato possa sfruttare la vulnerabilità XSS.

Se si richiede il caricamento di risorse esterne, assicurarsi di consentire solo gli script che non aiutano un utente malintenzionato a sfruttare il sito. Ad esempio, se si inseriscono nella whitelist determinati domini, un utente malintenzionato può caricare qualsiasi script da tali domini. Ove possibile, prova a ospitare risorse sul tuo dominio.

Se ciò non è possibile, è possibile utilizzare criteri basati su hash o nonce per consentire script su domini diversi. Un nonce è una stringa casuale che viene aggiunta come attributo di uno script o di una risorsa, che verrà eseguita solo se la stringa casuale corrisponde a quella generata dal server. Un utente malintenzionato non è in grado di indovinare la stringa randomizzata e quindi non può richiamare uno script o una risorsa con un nonce valido e quindi la risorsa non verrà eseguita.

Mitigazione degli attacchi XSS utilizzando CSP

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.