2010-05-08 10 views
25

Sto scrivendo il JS per un'applicazione di chat a cui sto lavorando nel mio tempo libero e ho bisogno di avere identificatori HTML che cambiano in base ai dati inviati dall'utente. Questo di solito è qualcosa di concettualmente abbastanza traballante che non proverei nemmeno a provarlo, ma non mi vedo più di avere molta scelta questa volta. Quello che devo fare è sfuggire all'ID HTML per assicurarmi che non permetta l'XSS o la rottura dell'HTML.Sanitizzazione dell'input dell'utente prima di aggiungerlo al DOM in Javascript

Ecco il codice:

var user_id = escape(id) 
var txt = '<div class="chut">'+ 
      '<div class="log" id="chut_'+user_id+'"></div>'+ 
      '<textarea id="chut_'+user_id+'_msg"></textarea>'+ 
      '<label for="chut_'+user_id+'_to">To:</label>'+ 
      '<input type="text" id="chut_'+user_id+'_to" value='+user_id+' readonly="readonly" />'+ 
      '<input type="submit" id="chut_'+user_id+'_send" value="Message"/>'+ 
      '</div>'; 

Quale sarebbe il modo migliore per sfuggire id per evitare qualsiasi tipo di problema di cui sopra? Come puoi vedere, in questo momento sto utilizzando la funzione integrata escape(), ma non sono sicuro di quanto dovrebbe essere buono rispetto ad altre alternative. Sono principalmente abituato a disinfettare l'input prima che vada in un nodo di testo, non un id stesso.

+0

Che cosa è esattamente la funzione di 'id'? – Tgr

+0

l'ID adesso è qualsiasi stringa che rappresenta un utente.Lo uso per differenziare strutture simili della pagina che appartengono a utenti diversi. da quella logica, MD5 o base64 potrebbe essere una buona attesa per farlo, credo. Non ci sono cose incorporate per questo. –

risposta

30

Mai utilizzare escape(). Non ha nulla a che fare con la codifica HTML. È più come la codifica dell'URL, ma non è nemmeno proprio così. È una bizzarra codifica non standard disponibile solo in JavaScript.

Se si desidera un codificatore HTML, è necessario scriverlo manualmente poiché JavaScript non ne fornisce uno. Per esempio:

function encodeHTML(s) { 
    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;'); 
} 

Tuttavia, mentre questo è sufficiente per mettere il vostro user_id in luoghi come il input value, non è abbastanza per id perché gli ID possono utilizzare solo una selezione limitata di caratteri. (E % non è tra questi, in modo escape() o addirittura encodeURIComponent() non va bene.)

Si potrebbe inventare il proprio schema di codifica per mettere tutti i caratteri in un ID, ad esempio:

function encodeID(s) { 
    if (s==='') return '_'; 
    return s.replace(/[^a-zA-Z0-9.-]/g, function(match) { 
     return '_'+match[0].charCodeAt(0).toString(16)+'_'; 
    }); 
} 

Ma voi hai ancora un problema se lo stesso user_id si verifica due volte. E ad essere onesti, l'intera cosa con il lancio di stringhe HTML è di solito una cattiva idea. Utilizza invece i metodi DOM e mantieni i riferimenti JavaScript per ogni elemento, quindi non devi continuare a chiamare getElementById o preoccuparti di come le stringhe arbitrarie vengono inserite negli ID.

es.:

function addChut(user_id) { 
    var log= document.createElement('div'); 
    log.className= 'log'; 
    var textarea= document.createElement('textarea'); 
    var input= document.createElement('input'); 
    input.value= user_id; 
    input.readonly= True; 
    var button= document.createElement('input'); 
    button.type= 'button'; 
    button.value= 'Message'; 

    var chut= document.createElement('div'); 
    chut.className= 'chut'; 
    chut.appendChild(log); 
    chut.appendChild(textarea); 
    chut.appendChild(input); 
    chut.appendChild(button); 
    document.getElementById('chuts').appendChild(chut); 

    button.onclick= function() { 
     alert('Send '+textarea.value+' to '+user_id); 
    }; 

    return chut; 
} 

Si potrebbe anche usare una funzione di convenienza o framework JS per ridurre il lungaggini del create-set-aggiunge chiamate lì.

ETA:

sto usando jQuery al momento come un quadro

OK, quindi prendere in considerazione i collegamenti di creazione di jQuery 1.4, ad es .:

var log= $('<div>', {className: 'log'}); 
var input= $('<input>', {readOnly: true, val: user_id}); 
... 

Il problema che ho adesso è che uso JSONP per aggiungere elementi ed eventi a una pagina, quindi non posso sapere se gli elementi già esistere o meno prima di mostrare un messaggio.

È possibile mantenere una ricerca di user_id di nodi elemento (o oggetti wrapper) in JavaScript, per salvare mettendo tali informazioni nel DOM per sé, in cui i personaggi che possono andare in un id sono limitati.

var chut_lookup= {}; 
... 

function getChut(user_id) { 
    var key= '_map_'+user_id; 
    if (key in chut_lookup) 
     return chut_lookup[key]; 
    return chut_lookup[key]= addChut(user_id); 
} 

(Il prefisso _map_ è perché gli oggetti JavaScript Non abbastanza lavoro di mappatura delle stringhe arbitrarie. La stringa vuota e, in IE, alcuni nomi dei membri Object, confondono.)

+0

Attualmente sto usando jQuery come framework, quindi qualsiasi idea relativa a ciò può essere utile. Il problema che ho adesso è che uso JSONP per aggiungere elementi ed eventi a una pagina, e quindi non posso sapere se gli elementi esistono già o meno prima di mostrare un messaggio. Questo mi ha fatto pensare che sono costretto a usare il metodo schifoso che devo trovare quali elementi selezionare o aggiungere se non ci sono già. Per questo motivo, non penso che il tuo ultimo suggerimento potrebbe funzionare, ma potrei sbagliarmi. Il set di caratteri limitato mi fa pensare che un MD5 dell'id potrebbe essere tutto ciò che posso fare. –

+0

Anche se potrei semplicemente aggiungere un'ipotesi sui caratteri accettati dei nomi utente, usare espressioni regolari e farlo. –

7

Si potrebbe utilizzare una semplice espressione regolare per affermare che l'id contenga solo caratteri consentiti, in questo modo:

if(id.match(/^[0-9a-zA-Z]{1,16}$/)){ 
    //The id is fine 
} 
else{ 
    //The id is illegal 
} 

Il mio esempio consente solo caratteri alfanumerici, e stringhe di lunghezza da 1 a 16, si dovrebbe cambiare per abbinare il tipo di ID che si utilizza.

A proposito, alla riga 6, alla proprietà value manca una coppia di virgolette, un errore facile da fare quando si cita su due livelli.

Non riesco a vedere il flusso di dati effettivo, a seconda del contesto questo controllo potrebbe non essere affatto necessario o potrebbe non essere sufficiente. Per fare una corretta revisione della sicurezza avremmo bisogno di più informazioni.

In generale, sulle funzioni di escape o disinfezione incorporate, non fidatevi ciecamente di esse. Devi sapere esattamente cosa fanno e devi stabilire che quello è effettivamente ciò di cui hai bisogno. Se non è quello che ti serve, il codice è tuo, il più delle volte una semplice regex di whitelist come quella che ti ho dato funziona bene.

1

È necessario prendere ulteriori precauzioni quando si utilizzano dati forniti dall'utente in attributi HTML. Poiché gli attributi hanno molti più vettori di attacco rispetto ai tag HTML.

L'unico modo per evitare attacchi XSS è codificare tutto tranne i caratteri alfanumerici. Elimina tutti i caratteri con valori ASCII inferiori a 256 con & #xHH; formato. Che sfortunatamente potrebbe causare problemi nel tuo scenario, se stai usando le classi CSS e javascript per recuperare quegli elementi.

OWASP ha una buona descrizione di come attenuare attributo HTML XSS:

http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.233_-_JavaScript_Escape_Before_Inserting_Untrusted_Data_into_HTML_JavaScript_Data_Values

12

Un altro approccio che mi piace è quello di utilizzare le funzionalità DOM native: http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript

+1

@BrandonMintern gist non funziona per me. – cmcculloh

+1

Ho scritto quel post sul blog. Sfortunatamente, la tecnica TL; DR fornita in alto non è appropriata per l'uso negli attributi HTML. Ci sono altri approcci verso la fine del post che escono correttamente anche per gli attributi HTML, ovvero: http://shebang.brandonmintern.com/foolproof-html-escaping-in-javascript/#hack-3-more-efficient -catchall –

1

poiché il testo che si sta l'escaping verrà visualizzato in un attributo HTML, devi essere sicuro di sfuggire non solo alle entità HTML ma anche agli attributi HTML:

var ESC_MAP = { 
    '&': '&amp;', 
    '<': '&lt;', 
    '>': '&gt;', 
    '"': '&quot;', 
    "'": '&#39;' 
}; 

function escapeHTML(s, forAttribute) { 
    return s.replace(forAttribute ? /[&<>'"]/g : /[&<>]/g, function(c) { 
     return ESC_MAP[c]; 
    }); 
} 

Quindi, il codice di escape diventa var user_id = escapeHTML(id, true).

Per ulteriori informazioni, vedere Foolproof HTML escaping in Javascript.

Problemi correlati