Ajax, user-experience e sicurezza. Una analisi dei concetti alla base delle nuove applicazioni Web
Ajax è la tecnologia che viene utilizzata per creare Web Applications interattive atte a fornire una modo totalmente nuovo d'interagire con contenuti e servizi.
Uno dei componenti "essenziali" di Ajax è l'oggetto Javascript XMLHttpRequest. Questo oggetto permette di inserire contenuto remoto da un server senza avere il bisogno di "refreshare" la pagina in cui esso è presente.
XmlHttpRequest è stato ideato pensando alla semplica ed intuitività d'impiego. Per esempio:
1: // Istanza XMLHttpRequest
2: var request = new XMLHttpRequest;
3: // Gestione delle risposte
4: request.onreadystatechange = function ()
5: {
6: if (request.readyState == 4)
7: {
8: // .. codice da eseguire ..
9: alert(request.responseText);
10: }
11: };
12:
13: // apre una request alla pagina aspx
14: request.open('GET', '/pagina.aspx', false);
15: // invia la richiesta
16: request.send(null);
Purtroppo, il modo in cui XMLHttpRequest è implementato in diversi browser non è lo stesso. Ci troveremo dunque, nel caso di Internet Explorer ad utilizzare il componente ActiveXObject("Msxml2.XMLHTTP") o in alcuni casi ActiveXObject("Microsoft.XMLHTTP") per utilizzare l'oggetto XMLHttpRequest.
Questo oggetto ha differenti metodi e proprietà. La lista che segue li elenca.
| Metodi/Proprietà | Descrizione |
| abort() | Annulla la richiesta |
| getAllResponseHeaders() | Recupera gli header di risposta in formato stringa |
| setRequestHeader(name, value) | Imposta il valore di un determinato header |
| open(method, URL) | Crea un oggetto di richiesta impostando il metodo che verrà utilizzato e l'url da cui verrà recuperato.
E' possibile specificare, come parametri opzionali, se si vuole creare una richiesta di tipo sincrona / asincrona e le credenziali per accedere alla richiesta nel caso in cui essa sia protetta. |
| onreadystatechange | Questa proprietà permette di gestire uno o più eventi che verrà scatenato durante il cambio di stati. |
| readyState | Parametro che definisce lo stato di una richiesta. I possibili valori, tutti numerici, sono
0 - non inizializzata |
| status | Indica lo stato di una risposta. I valori, numerici, possono essere (per esempio) 200 nel caso in cui la richiesta sia andata a buon fine o 302 nel caso in cui una reindirizzamento è necessario. |
| statusText | Questa proprietà ritorna la descrizione associata al codice di stato |
| responseText | Ritorna il contenuto della risposta ricevuta |
| responseXML | Simile a responseText, ad eccezione del fatto che ritorna la risposta è formattata DOM. |
responseText e responseXML sono due modi di rappresentare la risposta in formati quasi simili. Per esempio: XML ed HTML, pur essendo a prima vista differenti, sono concettualmente simili. Entrambi i modelli possono essere rappresentati su una radice gerarchica basata sugli standard definiti dal W3C. Questi standard definiscono come gli elementi devono essere creati e strutturati al fine di avere un documento valido. HTML, proprio come XML, può essere "parserizzato" in una struttura DOM.
La funzione getElementsByTagName, ritorna un array di elementi. Un altra funzione, getElementById, ritorna un singolo elemento basato sull'indentificatore passato come paramentro. Nel caso volessimo sostituire il contenuto di tutti i tag <p> all'interno di una pagina vulnerabile ad XSS potremmo eseguire il seguente codice.
1: // Recupera tutti i <p> presenti nella pagina
2: var p = document.getElementsByTagName('p');
3: // cicla la lista
4: for (var i = 0; i < p.length; i++)
5: {
6: // imposta il nuovo testo
7: p[i].innerHTML = 'all we love XSS!';
8: }
Similmente, possiamo agire sulla proprietà responseXML per visualizzare un alert, e quindi dimostrare la vulnerabilità.
1: // Creazione di una XMLHttpRequest
2: // Verificando il corretto oggetto ActiveX da usare
3: function getXmlRequestResponse ()
4: {
5: var xhr = null;
6: if (window.XMLHttpRequest)
7: {
8: xhr = new XMLHttpRequest();
9: } else if (window.createRequest)
10: {
11: xhr = window.createRequest();
12: } else if (window.ActiveXObject)
13: {
14: try
15: {
16: xhr = new ActiveXObject('Msxml2.XMLHTTP');
17: }
18: catch (e)
19: {
20: // Il carimento di Msxml2.XMLHTTP è fallito
21: // tentativo di creazione Microsoft.XMLHTTP
22: try
23: {
24: xhr = new ActiveXObject('Microsoft.XMLHTTP');
25: } catch (e)
26: {
27: // Fine ciclo di vita.
28: }
29: }
30: }
31: return xhr;
32: };
33:
34: // Istanza XMLHttpRequest
35: var request = getXmlRequestResponse();
36: // Gestione delle risposte
37: request.onreadystatechange = function ()
38: {
39: // Controllo stato (Success della request)
40: if (request.readyState == 4)
41: {
42: // eseguo codice in formato XML
43: alert(request.responseXML.getElementById('messaggio'));
44: }
45: };
46: // apre la request alla pagina.aspx
47: request.open('GET', '/pagina.xml.aspx', false);
48: // invia la richiesta
49: request.send(null);
Saper gestire XML ed Ajax è importante. Con il passare del tempo stanno diventando parte integrante d'internet. E' altresi importante capire l'impatto che queste tecnologie possono avere con il mondo della Web Application Security. Tecniche di testing e auditing sono in continua evoluzione.
Il rilevamento di XSS Injection points può essere un duro lavoro, ma con gli strumenti giusti e le skill necessarie è possibile trovarne in continunazione. Parleremo di questo nel prossimo post. Aloha.