XSS o Cross-Site Scripting

Il Cross-Site Scripting, comunemente abbreviato come XSS, è una vulnerabilità delle applicazioni web che permette a un attaccante di compromettere il normale utilizzo di un'applicazione. Nello specifico permette di

  • Assumere l'identità della vittima, permettendo quindi di rubare dati sensibili o eseguire azioni inattese.
  • Rubare credenziali di login o cookie di sessione.
  • Iniettare malware dentro il browser della vittima.
  • Se la vittima possiede un ruolo privilegiato nel contesto dell'applicazione, allora l'attaccante potrebbe ottenere il controllo totale della applicazione stessa e dei dati al suo interno.

Scendendo un po' più nel dettaglio, l'attacco XSS consiste nel iniettare codice Javascript malevolo all'interno del browser dell'utente vittima. Questo avviene tramite degli errori di programmazione nel codice Javascript di una applicazione web. Questi errori possono nascere da diversi assunti sbagliati o bad-practice durante la fase di sviluppo del codice.

Tipologie di XSS

Esistono tre tipologie principali di XSS. Queste sono:

  • Reflected XSS, dove il codice Javascript malevolo deriva dalla richiesta HTTP corrente.
  • Stored XSS, dove il codice Javascript malevolo deriva dal database dell'applicazione
  • DOM-based XSS, dove la vulnerabilità nasce dal codice client-side piuttosto che da quello server-side.

Reflected Cross-Site Scripting

Reflected XSS è la versione più semplice tra le tre tipologie. Nasce quando una applicazione riceve dati da una richiesta HTTP e include questi dati dentro la risposta senza applicare una sanificazione robusta o sufficiente.

Ad esempio

Richiesta: https://esempio.it/status?messaggio=oggi+piove

Risposta: <p>Status: Oggi piove</p>

L'applicazione non esegue alcun tipo di elaborazione dei dati, quindi un attaccante può facilmente costruire una richiesta che inietta codice HTML (e quindi Javascript) dentro la pagina.

Richiesta: https://esempio.it/status?messaggio=<script>alert(document.domain)</script>

Risposta: <p>Status: <script>alert(document.domain)</script></p>

Quindi, se un utente visitasse l'URL costruito dall'attaccante, lo script malevoloverrebbe eseguito nel contesto dell' applicazione web. A quel punto, lo script può eseguire qualsiasi azione e, per esempio, esfiltrare tutti i dati a cui l'utente ha accesso.

Stored Cross-Site Scripting

Stored XSS si verifica quando un'applicazione riceve dati da una fonte non attendibile e li include nelle sue risposte HTTP successive in modo non sicuro. Ad esempio, ipotizziaimo che un sito web consenta agli utenti di inviare commenti sui post all' interno di un blog, i quali verranno in seguito visualizzati da altri utenti. Gli utenti inviano commenti utilizzando una richiesta HTTP come la seguente:

POST /post/comment HTTP/1.1
Host: esempio.it
Content-Length: 100

postId=3&comment=Post+molto+interessaante

Dopo aver inviato il commento, ogni utente che visiterà il blog, potrà dunque leggere i commenti. Di conseguenza noterà un messaggio del tipo

<p>This post was extremely helpful.</p>

Come nel caso precedente, se l'applicazione non esegue alcun tipo di sanificazione sui dati inseriti dall'utente, un attaccante può inserire un commento del tipo

<script>alert(document.domain)</script>

Di conseguenza ogni utente che visiterà il post su cui è stato inserito questo commento sarà vittima del codice malevolo. Questo in quanto nella pagina HTML sarà visualizzato il codice seguente

<p><script>alert(document.domain)</script></p>

N.B Si noti che il payload usato qui è innocuo e a titolo dimostrativo. In ogni caso avere la possibilità di inserire codice Javascript arbitrario all'interno permette di fare numerosi azione malevole, come già spiegato all'inizio del capitolo.

Stored XSS vs Reflected XSS

Reflected XSS, seppur dannoso per un utente, richiede allo stesso di cliccare su un link malevolo. Solitamente quindi è necessario un click da parte dell'utente per innescare la vulnerabilità, e per questo motivo, in genere, la severità dei Reflected XSS è considerata Media.

D'altro canto, Stored XSS non richiede a un utente di cliccare su qualche link malevolo, ma può essere semplicemente innescato durante la normale navigazione di un sito vulnerabile. Per questo solitamente si parla di zero click e di conseguenza possiede una severità maggiore, generalmente categorizzata come Alta.

DOM-based Cross-Site Scripting

Prima di cominciare a parlare della vulnerabilità in se bisogna fare una premessa su cosa sia il DOM e su un paio di termini fondamentali per capire al meglio la vulnerabilità. Il Document Object Model, comunemente abbreviato con DOM, è la rappresentazione gerarchica, effettuata dal browser, degli elementi della pagina. Un sito web può utilizzare Javascript per manipolare i nodi e gli oggetti del DOM. Questo procedimento, se effettuato in modo scorretto, può portare a diversi tipi di attacchi.

DOM-based XSS, solitamente abbreviato come DOM XSS, si verifica quando il codice Javascript all'interno della pagina estrapola i dati da una fonte controllabile da un attaccante, come l'URL, e li inserisce all'interno di un sink che supporta esecuzione dinamica di codice. Tra questi sink possiamo trovare eval o innerHTML. Per effettuare un attacco di questo tipo è necessario semplicemente inserire dati malevoli dentro un source che verrà poi propagato in un sink dove il codice sarà eseguito. Il source più comune in assoluto è l'URL che viene referenziato all'interno di Javascript tramite l'oggetto window.location.

Source e Sink

Un source è una proprietà di un oggetto Javascript che accetta dati potenzialmente controllabili da utente. Un esempio di source è location.search perché legge i dati dalla query, la quale è relativamente semplice da controllare.

Un sink, invece, è una funzione Javascript o un oggetto del DOM che causa effetti indesiderati se soggetta a dati inseriti da un utente malevolo. Ad esempio la funzione eval() perché esegue qualsiasi cosa le venga passata come codice Javascript. Invece, un esempio di sink HTML è document.body.innerHTML perché permette a un utente di inserire codice HTML arbitrario.

Content-Security Policy

Introduciamo ora un meccanismo di difesa che tutti i browser moderni offrono per mitigare l'impatto di un XSS nell'ipotesi che esso avvenga: la Content-Security Policy, comunemente chiamata CSP. Il suo funzionamento consiste nel restringere le risorse che una pagina può caricare (come script o immagini) e nel restringere quali domini possano utilizzare la pagina come iframe. Per abilitare la CSP una risposta HTTP deve includere un Header del tipo Content-Security Policy con il suo valore corrispettivo. Ad esempio la direttiva script-src 'self' permette di caricare script che derivano dall stessa origine della pagina stessa.

La CSP è altamente personalizzabile, per questo bisogna prestare molta attenzione al tipo di CSP che si va a implementare. Per esempio, includere nella CSP un Content-Deilivery Network (CDN) come ajax.googleapis.com potrebbe essere pericoloso in quanto utenti di terze parti potrebbero includere i loro script malevoli all'interno della CDN. Così facendo verrebbe vanificato completamente l'applicazione della CSP.