XSS via JSON: perché un'applicazione web non disinfetta il suo hash dei parametri in arrivo oi suoi valori JSON in uscita di tag dannosi come Script?

10

Recentemente lavorando a un'applicazione Web basata su Rails per un'azienda, ho dovuto esaminare la vulnerabilità XSS. Risulta che l'applicazione, in alcuni punti, potrebbe prendere un tag HTML (ad es., <script>jscodehere</script> direttamente come parametro nelle richieste GET o POST.

Questo parametro è quindi accessibile tramite l'hash dei parametri dell'applicazione (l'hash in cui tutti i dati chiave / valore entrante sono resi disponibili dalla richiesta).

Ora, la vulnerabilità XSS derivava dal fatto che il sito rende disponibili anche i dati di molte delle sue pagine in una versione JSON (ad esempio /cart/1.json ).

Attraverso alcuni meccanismi che non capisco appieno (suppongo che questo sia tecnicamente "Reflected XSS"?), il codice <script> non salvato che è poi entrato nel JSON può essere usato per compromettere le macchine personali e altri siti , attraverso l'esecuzione involontaria.

La mia domanda è: perché questo non è un sistema opt-in? Rails è ora nella versione 4, quindi sono sorpreso che una soluzione debba ancora essere costruita manualmente, ma ciò si applicherebbe a qualsiasi framework di applicazione web. Una cosa è permettere ai param di entrare in unsanitized di default (forse i tag HTML saranno usati nella pagina del profilo di un utente e la formattazione è richiesta) - e penso che Rails faccia anche un po 'di scrubbing sull'effettiva azione di rendering, limitando l'output , per impostazione predefinita, solo i tag html "sicuri".

Tuttavia, durante il rendering di JSON, non esegue tale sanitizzazione / pulizia, forse perché quando la risposta JSON viene creata e analizzata è troppo personalizzata per farlo, ma non capisco perché

1) Alcuni meccanismi incorporati non sono in posizione

2) Di questo non si parla più - non ho trovato alcuna discussione sul passaggio non sicuro dei tag HTML / Script nel rendering JSON dalle app Rails o Sinatra sul web (ho potuto trovare solo una piccola quantità di informazioni su Sanitizing l'hash params, quindi i valori di sanificazione sul modo IN, che è probabilmente migliore, ma potrebbe non funzionare per tutto, in quanto è una soluzione valida per tutti, si consiglia di conservare alcuni tag HTML ma solo strip out <script> tag, ad esempio).

3) Perché, nel mondo Ruby, almeno, esiste attualmente una sola libreria che esiste per sanitizzare (la Sanitize Gem, e funziona davvero solo con i tipi di dati String - devi scrivere il tuo codice ricorsivo per disinfettare un hash, come l'hash params, e sembra che non ci sia nulla di scritto su questo!). Rails ha un disinfettante incorporato, ma è considerato inferiore a questo Sanitize Gem di terze parti, e non è così flessibile quando si tratta di avere alcuni livelli di rigidità in quanto profondamente sanificare (una stringa).

Sto fraintendendo la validità dell'iniezione in JSON come vulnerabilità, o questa vulnerabilità è stata in gran parte trascurata perché JSON non è una caratteristica principale di tutte le applicazioni web?

Risultato finale: ho usato un filtro precedente nel controller principale dell'applicazione sul back-end per disinfettare l'hash params ogni volta che arriva da una richiesta, usando la libreria Sanitize.

Tuttavia, ritengo che questo abbia rallentato in modo significativo l'applicazione perché deve verificarsi su ogni richiesta e il Sanitizer esegue essenzialmente una serie di chiamate regex in modo ricorsivo sull'hash. In questo modo nessun tag entra mai nel database, e non può mai realizzarlo tramite JSON, ma è un risultato costoso dal punto di vista delle prestazioni. C'è un modo migliore?

    
posta rcd 19.12.2015 - 10:05
fonte

2 risposte

8

Questo è spesso portato dappertutto, in parte perché tutti continuano a ripetere il mantra secondo cui l'input igienico-sanitario è la risposta. Non lo è. È pericoloso, soggetto a bug e ha bisogno di andare via. Certo, dovresti sempre verificare se le lunghezze di input corrispondono correttamente alle colonne appropriate.

Disinfezione dell'ingresso rispetto all'uscita di disinfezione.

L'input di disinfezione dà alle persone un falso senso di sicurezza poiché ci sono così tanti modi per aggirarle e perché è difficile implementarle correttamente, costringendo gli sviluppatori a cercare su google un'implementazione obsoleta che potrebbe essere o meno sicura. Per questo motivo, è meglio disinfettare output .

Parte del motivo per cui questo viene fatto in seguito è perché si desidera conservare i dati corretti, ma anche proteggere dagli attacchi SQL injection. Gli attacchi di SQL injection sono in gran parte sconfitti da dichiarazioni preparate, in realtà non igieniche. Dovresti sostituire tutti i tag script e gli output pericolosi con entità html .

Ecco un esempio di sostituzione di potenziali caratteri di script con entità html in output, non in input:

  1. < diventa &lt; , viene ancora visualizzato come < sulla pagina, ma senza problemi con il layout o il database.

  2. > diventa &gt; , viene ancora visualizzato come > sulla pagina, ma senza problemi con il layout o il database.

Quindi, perché non disinfettare l'input? Cosa fare se lo implementiamo correttamente?

La maggior parte degli sviluppatori non sono esperti di sicurezza IT. La maggior parte degli sviluppatori non avrebbe idea di cosa fare in quest'area. Insegnando loro questi due metodi comuni di protezione dei dati, si risparmiano tempo di sviluppo e si aumenta in modo significativo la sicurezza generale della propria applicazione web. Meglio ancora, aiuti i tuoi sviluppatori a capire perché è necessario, invece del perché 2340939403424 sono necessari diversi tipi di servizi igienico-sanitari e previeni molti problemi di implementazione che invariabilmente appariranno in seguito.

Come ho detto prima, la ricerca di google per le funzioni di risanamento dei dati obsolete non è la sicurezza. Questo è un falso senso di sicurezza. Devi capire cosa è accettabile e cosa no e il processo che i dati attraversano.

Con i servizi igienico-sanitari in uscita, non devi preoccuparti di qualche bug strano accaduto in seguito lungo la strada che ti sei dimenticato. Non è necessario fare confusione con tonnellate di funzioni complicate che potrebbero essere implementate in modo errato e dare un falso senso di sicurezza. Non ti devi preoccupare degli script in corso di iniezione.

Ma cosa succede se sostituiamo tutte le entità html prima che vengano inserite? Se lo provi dal lato del cliente, chiunque potrebbe modificare la richiesta. Se lo controlli sul back-end prima di metterli nel database, potrebbe funzionare anche ... ma poi c'è un problema :

Che cosa succede se c'è un campo che richiede l'inserimento di un'entità HTML effettiva su di esso? Diciamo una confezione, un indirizzo o qualcosa di stupido come quello. Forse è un nome di file, forse è qualcosa che hai implementato in un modo.

Esempio di motivo per cui la sanitizzazione degli input schiaccia

Forse qualcuno ha una tastiera divertente che usa un diverso apostrofo per il loro nome o indirizzo? Ciò potrebbe lasciare alcuni database aperti al contrabbando basato su Unicode.

Forse hai bisogno di un record che ha < or > al suo interno? Che cosa hai intenzione di fare? Cerca dall'entità Html? Questo è abbastanza inefficiente e richiede un sacco di hack per funzionare correttamente in molti database.

Forse il nome di qualcuno ha un apostrofo in esso, ad esempio Rory O'Cune . Con il risanamento dei dati, stai distruggendo il suo nome e richiedendo più codice per affrontarlo. Cosa succede se uno dei tuoi dipendenti sta cercando per cognome e non riesce a trovarlo perché è stato ridotto a OCune ? È terribile.

Questo è un altro motivo per cui si utilizzano query con parametri e non si apportano misure igieniche. Con le dichiarazioni preparate e l'igienizzazione dei risultati, puoi fare ciò:

SELECT * FROM [table] WHERE [last_name] = @Lastname -- (or ?)

La variabile @Lastname (sarebbe un ? in Java) sarà correttamente tradotta in O'Cune . Non sono richiesti affari divertenti. Nessun bug da cacciare. È infinitamente più sicuro e puoi solo generare html entity se è un personaggio che rompe le pagine.

Quindi, perché Ruby non lo aggiusta automaticamente?

Perché dovrebbero? Devo ancora trovare implementazioni di JSON in qualsiasi lingua che rimuoverà automaticamente questi tag di script. Cosa succede se si desidera utilizzare JSON per visualizzare tag di script per qualche strana ragione sul tuo sito web?

Rimuovendo questa funzione, impedisci a chiunque di trasmettere HTML attraverso JSON, che sospetto possa rompere un sacco di cose per molte persone.

Quindi, la risposta è di farlo te stesso . Sostituisci i tag script con le entità Html prima che vengano serializzati e restituiti.

    
risposta data 19.12.2015 - 23:31
fonte
8

Fare gli input sicuri è meglio farlo il più tardi possibile. Cioè, quando i dati vengono inviati alla pagina. I dati di input "disinfettanti" a livello globale sono negativi perché è impossibile distinguere tra dati validi e dati non validi in questa fase (come dici tu, se stai consentendo l'inserimento dell'HTML da parte degli utenti, il framework non può dire la differenza tra HTML che deve essere lì vs HTML che non lo è). Anche con lo script in input a volte questo può essere valido (si pensi alle caselle di testo StackOverflow / StackExchange contenenti codice).

Il più tardi possibile, l'applicazione deve essere codificata in qualsiasi formato l'output sia. Ad esempio, HTML o JSON. Con il segno ex e & diventa &amp; in modo che venga visualizzato correttamente per la visualizzazione, per quest'ultimo deve essere utilizzato un codificatore JSON che converte & in \x26 all'interno di una stringa JSON.

Lo stesso JSON non è un rischio XSS poiché lo script non viene eseguito in un browser da una richiesta JSON (JSONP è un altro argomento poiché questi sono inclusi con i riferimenti src dello script anziché caricati come dati). Il rischio XSS con JSON è quando JavaScript sulla pagina tenta di creare o popolare elementi HTML con i dati JSON recuperati. Lo stesso JavaScript deve o HTML codificare i dati o utilizzare membri di oggetti sicuri per popolare il DOM (ad esempio textContent ).

La sanitizzazione può essere eseguita come livello aggiuntivo, tuttavia la codifica appropriata dovrebbe essere l'obiettivo. Ad esempio, potresti voler convalidare lato server che un codice postale o un codice postale contiene solo caratteri alfanumerici e il carattere spazio. Per i campi più complessi, questa non è un'opzione senza limitare drasticamente le tue capacità di input.

Alcuni framework tentano di sanificare globalmente i dati, come .NET con l'uso di richiesta di convalida . Tuttavia, le vulnerabilità sono sempre presenti, tra cui questa recentissima . In breve, non funziona e causa problemi funzionali alle lingue che lo tentano. Inoltre, non offre alcuna protezione da XSS nei dati che vengono recuperati da altre fonti rispetto all'applicazione stessa.

    
risposta data 19.12.2015 - 10:35
fonte

Leggi altre domande sui tag