Whitelisting elementi DOM per sconfiggere XSS

13

Come sappiamo, gli sviluppatori sono responsabili della corretta escaping / validazione dei dati forniti dall'utente prima di renderli o memorizzarli. Tuttavia, dobbiamo convenire che è relativamente facile dimenticare un singolo input tra centinaia e, infine, ottenere l'app Web sfruttata da un XSS. Oppure non hai incontrato qualcuno che ha sfruttato il suo sito XSS?

Anche Twitter e Orkut hanno recentemente sofferto di XSS. E non sono qui per incolpare nessuno.

Supponiamo che il tuo browser supporti gli elementi DOM di whitelisting. Questi elementi autorizzati sono gli unici elementi consentiti per eseguire JavaScript. Ti rendi presto conto che sembra folle perché è impossibile mantenere il tuo sito Web preferito funzionando correttamente se hai una whitelist generica. E tu hai ragione!

Ma ora supponiamo che i motori HTML e JavaScript supportino una sintassi per consentire di autorizzare elementi del tuo sito web. Ad esempio:

<head>
    <script type="text/javascript">
        document.allowJavaScript(['div.item', '#list', 'a.navigate']);
    </script>
</head>

Questo non risolve il problema del rendering dei tag <script> nel mezzo di un albero DOM, ma questo è molto più facile da risolvere, suppongo.

Oltre al punto precedente, che tipo di problemi o difetti vedi nella soluzione descritta?

UPDATE 1 : solo l'elemento head deve essere considerato attendibile per richiamare allowJavaScript .

UPDATE 2 : si spera che il seguente snippet spieghi la mia idea un po 'oltre:

<html>
<head>
    <style>
        div.outer { background-color: #aaa; width: 200px; height: 100px; }
        div.inner { background-color: #5ff; width: 100px; height: 50px; }
        ul { list-style-type: none; }
        li { background-color: #bbc; border: 1px solid #fff; float: left;
            width: 100px; height: 30px; }
    </style>
    <script type="text/javascript">
        document.allowJavaScript(['div.outer', '#list', 'a.test']);
        function register_events() {
            var list = document.querySelector('#list');
            list.onclick = function() { alert('list'); }
            var example1 = document.querySelector('#list li:nth-of-type(1)');
            example1.onclick = function() { alert('example 1'); }
        }
        window.onload = register_events;
    </script>
</head>
<body>
    <div class="outer" onclick="alert('outer');">
        <div class="inner" onmouseover="alert('inner');">
        </div>
    </div>
    <a class="navigate" href="#" onclick="alert('a');">click me</a>
    <ul id="list">
        <li>example 1</li>
        <li>example 2</li>
    </ul>
</body>
</html>

Questo NON dovrebbe consentire l'esecuzione di:

  1. alert('inner') - > consenti div.outer , ma nessuno dei suoi elementi figli;
  2. alert('example 1') - > consenti #list , ma nessuno dei suoi elementi figli;
  3. alert('a') - > consenti a.test , non a.navigate ;
posta jweyrich 20.12.2010 - 12:13
fonte

7 risposte

8

Limitazione della whitelist al < head > l'elemento non è utile perché < title > è parte di < head > e spesso contiene dati forniti dall'utente. Pertanto, la definizione di white list deve essere il primo elemento di < head > e solo la prima chiamata alla whitelist può essere accettata.

Il contenuto di < li > esempio 1 < / li > non è considerato affidabile nell'esempio. Quindi un utente malintenzionato potrebbe fornire questo:

<li>example 1><a class="test" onmouseover="alert(document.cookie)">hello</a></li>

Poiché a.test si trova nella whitelist, il codice viene eseguito. Sarebbe possibile applicare una rigorosa convalida dell'elemento dom. Ma probabilmente vuoi consentire alcuni elementi nidificati come < b > e < i >.

Sembra molto più semplice evitare i contenuti non attendibili in base a una whitelist di tag e attributi consentiti.

PS: tieni presente che ci sono altre cattivezze come JavaScript incorporato nei CSS e plugin come flash e java.

    
risposta data 25.12.2010 - 13:40
fonte
14

JavaScript è un linguaggio lato client.

Nel mio parere professionale, avere fiducia in QUALSIASI implementazione del lato client per una maggiore sicurezza è una perdita di tempo, e l'implementazione sarebbe un grosso spreco di risorse.

Il tempo e il denaro saranno meglio utilizzati implementando una corretta pulizia e convalida dell'input sull'ambiente server-side.

    
risposta data 20.12.2010 - 20:03
fonte
10

Hai visto il lavoro di Sicurezza dei contenuti (riepilogo) di Mozilla Security ?

?

Questa è la specifica .

Content Security Policy is intended to help web designers or server administrators specify how content interacts on their web sites. It helps mitigate and detect types of attacks such as XSS and data injection. CSP is not intended to be a main line of defense, but rather one of the many layers of security that can be employed to help secure a web site.

Ho aggiunto l'enfasi alla clausola parlando di non affidarmi troppo al CSP.

Ecco alcuni esempi di criteri:

Sample Policy Definitions

Example 1: Site wants all content to come from its own domain:

X-Content-Security-Policy: allow 'self'

Example 2: Auction site wants to allow images from anywhere, plugin content from a list of trusted media providers (including a content distribution network), and scripts only from its server hosting sanitized JavaScript:

X-Content-Security-Policy: allow 'self'; img-src *; \ object-src media1.com media2.com *.cdn.com; \ script-src trustedscripts.example.com

Example 3: Server administrators want to deny all third-party scripts for the site, and a given project group also wants to disallow media from other sites (header provided by sysadmins and header provided by project group are both present):

X-Content-Security-Policy: allow *; script-src 'self' X-Content-Security-Policy: allow *; script-src 'self'; media-src 'self';

Sembra che impostare la politica di sicurezza nelle intestazioni, mentre non è inespugnabile attaccare, rende molto più difficile l'aggiunta della politica di sicurezza in linea nel DOM in cui potrebbe essere mutata.

Penso che la tua idea / domanda sia buona a cui pensare, ma quando inizi a fare in modo sempre più completo arriva un punto in cui è troppo costoso fare bene.

Ho avuto un'idea simile quando mi sono reso conto di quanto sia fastidioso che tutte le risorse dovrebbero essere pubblicate su SSL se si suppone che la pagina sia protetta da SSL. Il mio primo pensiero è stato l'idea di avere dei checksum per ogni risorsa che è possibile caricare sulla pagina SSL (caricarli in chiaro renderebbe più facile memorizzarli nella cache). Ovviamente ci sono una serie di problemi di sicurezza per farlo e alla fine sono arrivato alla conclusione che qualsiasi guadagno di prestazioni è rapidamente perso per problemi di sicurezza e complessità. Posso vedere come una whitelist DOM potrebbe soffrire rapidamente allo stesso modo.

Un ultimo punto : se hai abbastanza conoscenze da autorizzare sul lato browser, perché non puoi eseguire la whitelist sui dati che stai servendo prima di inviarli al browser?

    
risposta data 26.12.2010 - 06:53
fonte
8

Mi sembra un'idea interessante ma, dal momento che mi stai chiedendo dei problemi, risponderò ad alcuni di quelli ovvi. Non vedo come questo possa essere applicato globalmente alla maggior parte dei siti, poiché la maggior parte sembrerebbe aver bisogno di molte delle pericolose funzioni javascript disponibili per le funzionalità di base. Per esempio. onmouseover, href="javascript: alert (1)", ecc. Perché ciò sia utile in alternativa a Caja o JSReg o JSandbox potrebbe essere necessario applicare a qualsiasi livello nel DOM. Ad esempio se volessi solo proteggere il mio contenuto <div name="untrusted"> .

    
risposta data 20.12.2010 - 19:00
fonte
7

XSS di solito funziona iniettando JavaScript straniero nel corpo della pagina fidata. Se ti fidi del tuo codice che dice document.allowJavaScript(['div.outer', '#list', 'a.test']); come non ti fidi del codice sull'altra pagina del sito dicendo document.allowJavaScript(['div.evil', '#securityhole', 'a.exploit']); che è prodotto da una vulnerabilità XSS? Finché entrambi risiedono nello stesso contesto della stessa pagina - che è l'idea principale di XSS - non hai modo di conoscerne uno dall'altro.

Potresti, ovviamente, dire che hai un contesto "privilegiato" - diciamo, dentro <head> - e "non privilegiato" all'interno di <body> - e questo coprirà parte della vulnerabilità, ma non tutto. Dal momento che non hai modo di garantire che non ci sarà la vulnerabilità XSS che permetterebbe di iniettare il contenuto nella parte "privilegiata" della pagina. Certo, quelli sarebbero meno frequenti, ma non risolverebbero l'intero problema: dovresti comunque avere la convalida sul server.

Inoltre, si introdurrebbe un problema di manutenzione: ogni volta che il progettista modifica qualcosa nella pagina, è necessario modificare l'elenco degli elementi privilegiati, mantenendo allo stesso tempo le parti "dinamiche". Ciò potrebbe rivelarsi piuttosto difficile da fare in progetti reali, specialmente perché alcune pagine sono composte da molti widget indipendenti generati da parti separate dell'applicazione, che possono essere prodotti da team completamente diversi.

    
risposta data 25.12.2010 - 07:23
fonte
6

Dato il tuo interesse, ti incoraggio a leggere su Ter Louw e Vernkatakrishnan's Blueprint , Interpolique di Dan Kaminsky e Mozilla Content Security Policy. Consulta anche auto-escape con riconoscimento del contesto , come implementato in ctemplate di Google . C'è un sacco di fantastici lavori precedenti: assicurati di non reinventare la ruota.

I lavori precedenti su Blueprint e BEEP mostrano che il rischio di politiche di sicurezza in linea (come nella proposta) è che un'iniezione XSS può consentire a un utente malintenzionato di iniettare nuove politiche. Cosa succede se un utente malintenzionato inietta un nuovo tag HEAD e quindi aggiunge uno script al suo interno che richiama allowJavaScript?

Il lavoro precedente mostra anche che l'interruzione dell'esecuzione di Javascript non è sufficiente per essere sicuro. Se un utente malintenzionato può inserire materiale arbitrario nella pagina HTML, l'autore dell'attacco può essere in grado di: (i) montare attacchi di estrazione dati (ad esempio, acquisire token CSRF o segreti sulla pagina), (ii) sfigurare la pagina, (iii) phishing i tuoi utenti o rubare le credenziali di autenticazione (pensa di aggiungere un modulo di login che chiede all'utente il loro nome utente e password, ma dove l'azione del modulo viene inviata al sito dell'attaccante), (iv) monta attacchi CSRF (pensa a un'immagine in linea oa un elemento di forma che carica automaticamente un URL sul sito della vittima, o che inganna l'utente a farlo), (v) attacchi di clickjacking / strokejacking (alcuni dei quali non richiedono Javascript).

I lavori precedenti hanno anche dimostrato che gli attacchi sono possibili, senza eseguire alcun Javascript, attaccando i CSS. Vedi il documento di Huang, Weinberg, Evans e Jackson in CCS 2010. Il tuo schema sarà probabilmente vulnerabile a questo, se esiste qualche punto di iniezione nel documento, almeno su alcuni browser.

Infine, se autorizzi elementi nel DOM, cosa impedisce a un utente malintenzionato che inserisce nella pagina HTML di aprire e chiudere tag finché i loro dati dannosi non si trovano nel contesto dell'elemento autorizzato? Ad esempio, se la tua politica dice che lo script è permesso nel 2 ° tag P sotto il 1 ° DIV sotto il BODY, e se c'è un punto di iniezione subito dopo il primo tag P, allora un attaccante potrebbe iniettare </P><P><DIV><SCRIPT>alert('nasty')</SCRIPT> , e ora il il brutto script dell'attaccante verrà trattato dal browser come parte della parte bianca della pagina.

Raccomandazione generale: non consiglierei di fare affidamento su questa difesa. Ha un certo numero di punti deboli.

    
risposta data 07.01.2011 - 03:50
fonte
1

Qualcuno mi ha indirizzato alla tua domanda perché ne avevo una molto simile ma (finora) senza la possibilità di sfondare:
link

Forse insieme troveremo una buona soluzione;)

    
risposta data 02.05.2011 - 00:32
fonte