MasterDrive.it   
Vai indietro   MasterDrive.it > Web Development e Scripting > PHP > PHP Tutorials & How-To



Rispondi
 
Strumenti della discussione Modalità di visualizzazione
Vecchio 12-09-2007, 12:12   #1 (permalink)
Moderatore Globale

 L'avatar di Master85

 
4,465 Messaggi

Master85 e' decisamente importante ( + 350 )Master85 e' decisamente importante ( + 350 )Master85 e' decisamente importante ( + 350 )Master85 e' decisamente importante ( + 350 )
PHP 5.x: Nozioni di sicurezza

Indice degli argomenti:
Introduzione

Un ringraziamento particolare per la stesura di questo articolo va a Matteo ( Bottomap )

Le argomentazioni relative agli aspetti sulla sicurezza riguardanti lo sviluppo di applicazioni, rappresentano oggi una delle tante problematiche da valutare bene durante la progettazione e lo sviluppo di applicazioni orientate al web, per il semplice motivo che soluzioni del genere residenti su web server e dunque teoricamente accessibili a chiunque, sarebbero maggiormente piu' esposte a vari tipi di attacchi rispetto alle tradizionali applicazioni desktop, disponibili esclusivamente su determinati terminali client a deteminati “utenti” e dunque una percentuale di rischi sulla sicurezza minore, almeno teoricamente.
Sebbene la completa e perfetta “sicurezza” nell'ambito dei sistemi informatici e' pura utopia, esistono diverse tecniche e soluzioni specifiche per prevenire possibili attacchi e ridurre in questo caso, rischi e danni verso le nostre applicazioni web.
PHP rientra attualmente tra i linguaggi di programmazione web, piu' diffusi, seguiti e utilizzati al mondo, per lo sviluppo di siti dinamici e/o complete applicazioni web. Negli ultimi tempi, l'argomento relativo alla sicurezza, ha suscitato un enorme interesse tra i vari programmatori che utilizzano questo linguaggio, difatti, esempi negativi come le innumerevoli falle di sicurezza su sistemi Open Source, come il noto forum di discussione phpBB 2.x e nuove tecniche di cracking, come: XSS ( Cross Site Scripting ) per il defacing di siti web; SQL Injection ( Iniezioni sulle SQL ) per alterare i risultati o manipolare informazioni residenti su Database; Bot Automatici per la compilazione e l' invio di moduli web per la generazione di messaggi SPAM; E tante altre tecniche, hanno incentivato tanti programmatori sparsi in tutto il mondo, a diffondere tantissimi articoli, testi completi, documentazioni ufficiali e anche creazione di comunita' specifiche sulla sicurezza in PHP, all'organizzazione di convegni e a tanto altro ancora per evidenziare l'importanza di questo argomento, purtroppo ancora oggi, sottovalutato e spesso ignorato dai neofiti del settore. L' articolo che segue, nasce dalla volonta' di master85 e bottomap nel fornire un documento italiano abbastanza completo riguardo gli aspetti della sicurezza nel campo dello sviluppo web PHP, che possa approfondire alcuni tra gli argomenti piu' importanti riguardanti la sicurezza di applicazioni web sviluppate in PHP, si discutera' in modo particolare sul linguaggio di programmazione, senza considerare le configurazioni dei web server, permessi sul filesystem e specifici sistemi operativi. Nel corso dell'articolo verranno forniti inoltre una serie di riferimenti a siti o documenti esterni, sullo stesso argomento, da prendere seriamente in considerazione. Nello specifico andremo a soffermarci sui seguenti argomenti: register globals, magic quotes, filesystem, database e SQL injection, error reporting, prevenire lo SPAM, difenderci dal Cross Site Scripting ( XSS ) e la codifica dei Dati.

Register Globals

La direttiva “register globals” fa parte dell'insieme dei tanti parametri di configurazione del linguaggio ( file di configurazione php.ini ) che nelle ulime versione del PHP, dalla 4.2.0 in poi, viene impostato a OFF. Precedentemente impostato a ON, consentiva la registrazione di tutte le variabili EGPCS ( Environment, GET, POST, COOKIE, SERVER ) a livello globale all'interno del codice. Cio' consentiva allo sviluppatore di scrivere codice piu' velocemente ma allo stesso tempo poco sicuro, sebbene fosse piu' facile considerare qualsiasi variabile come variabile globale e quindi evitare di specificare la fonte, sia essa GET, POST o altra, allo stesso tempo, lo script appena scritto poteva essere soggetto ad attacchi di Injection delle stesse variabili e quindi scavalcare in tutta facilita' numerosi controlli di “sicurezza” e/o immettere dati falsati, per esempio sostituire tutte le variabili POST inviate da una form, con una serie di variabili GET impostate direttamente nella URL come querystring. Di seguito viene proposto un esempio concreto della direttiva “register globals”:

Codice PHP:
<?php
if ( isset($myVar) ) {
    echo 
"La variabile e' inizializzata, buon lavoro.";
} else {
    echo 
"La variabile non e' inizializzata. Impossibile continuare";
}
?>
Nel caso in cui la direttiva “register globals” fosse impostata ad OFF, il seguente script visualizzerebbe a video sempre e comunque lo stesso messaggio “La variabile non e' inizializzata. Impossibile continuare”, ma, nel caso in cui attivassimo la direttiva ad ON, sarebbe sufficiente scavalcare il controllo aggiungendo nella barra degli indirizzi questo valore: “myScript.php?myVar=1”, in questo caso la variabile myVar e' inizializzata al valore 1, di conseguenza il controllo del nostro script non avrebbe piu' tanta importanza.

Questo e' semplicemente uno dei tanti scenari in cui potremo trovarci, e' da ricordare che la direttiva “register globals” non e' configurabile a runtime, dovremo quindi chiedere informazioni a riguardo al nostro provider, oppure ricorrere alla funzione ini_get('register_globals') per controllare se la direttiva e' attiva o meno.

Inoltre, e' consigliabile sempre inizializzare qualsiasi variabile utilizzata all'interno del nostro codice e ricorrere alle variabili predefinite messe a disposizione dal PHP per recuperare i vari tipi di dati inviati tramite GET, POST, SESSION o COOKIE, ad esempio: $_GET['nome_variabile'] per recuperare i dati inviati tramite querystring da URL oppure $_POST per il recupero dei dati inviati tramite FORM e cosi' via. A questo indirizzo http://www.php.net/manual/en/languag...predefined.php e' possibile consultare la documentazione ufficiale PHP sull'utilizzo delle variabili predefinite.

Magic Quotes

Le “Magic Quotes” rappresentano un processo automatico offerto da PHP, in grado di aggiungere i caratteri di "escapes" ( backslashes "\" ) a tutti i dati provenienti dall'esterno verso script PHP. Come la documentazione ufficiale sul PHP suggerisce, e' preferibile lavorare e quindi scrivere del codice con la direttiva "magic_quotes_gpc" ad off e quando necessario ricorrere alla direttiva "magic_quotes_runtime". La scelta sull'utilizzo di una direttiva o l'altra e' obbligata dal provider che offre il servizio di Hosting oppure, dal file di configurazione php.ini, qualora fossimo noi stessi gli amministratori del web server.

Quando si fa riferimento all'argomento "Magic Quotes" e' bene tenere presente le tre direttive principali che lo compongono e quindi distinguere:

magic_quotes_gpc - La direttiva, come l'abbrevizione indica "_gpc" ha effetto su tutti i dati di tipo GET, POST e COOKIE, non puo' essere impostata a runtime e nelle ultime versioni del PHP e' settata al valore "on" come default. Quando questa direttiva e' abilitata tutti i singoli apici ( ' - Single Quote ), doppi apici ( " - Double Quote ), \ ( Backslash ) ed i caratteri Nulli vengono anteceduti dal carettere \ ( Backslash ) di conseguenza la frase - l'albero e' verde - viene trasformata in - l\'albero e\' verde. Per capire se la direttiva magic_quotes_gpg sia abilitata o meno sul server, e' necessario ricorrere alla funzione get_magic_quotes_gpc(), ritornera' 0 in caso sia disattivata o 1 in caso contrario. E' bene ricordare che la direttiva magic_quotes_gpc non puo' essere impostata a runtime;

magic_quotes_runtime - Se questa direttiva viene abilitata, la maggior parte dei dati restituiti da funzioni che elaborano fonti di dati esterni, come file di testo o database, dati GET, POST o COOKIE, presentaranno tutti i caratteri come singoli apici, doppi apici, backslash oppure caratteri nulli, anteceduti da un \ ( backslash ). La direttiva in questione e' impostata di default ad off e puo' essere settata a runtime mediante la funzione set_magic_quotes_runtime(valore) dove valore e' un valore numerico compreso tra 0 e 1, rispettivamente disabilitano e abilitano la direttiva. Invece, per controllare lo stato attuale della direttiva direttamente da codice, si ricorre alla funzione get_magic_quotes_runtime() che ritornera' 1 in caso sia attiva e 0 in caso contrario;

magic_quotes_sybase - Quest'ultima direttiva, se attiva, sovrascrive completamente la precedente magic_quotes_gpc e tutti i singoli apici ( ' ) verranno anteceduti da un ulteriore singolo apice ed inoltre tutti gli altri caratteri come doppi apici, backslash e valori nulli resteranno inalterati.

I motivi che spingono gli sviluppatori PHP ad usufruire delle direttive Magic Quotes sono principalmente due: Convenienza e Utilita' - utile durante la creazione di SQL e dunque l'inserimento di dati nel database, evita di ricorrere all'utilizzo della funzione addslashes() per prevenire errori di sintassi su dati che presentano caratteri speciali che necessitano di essere anteceduti da "backslash", come GET o POST ed inoltre, riduce i rischi di eventuali attacchi di tipo "Iniezioni SQL" ( SQL Injection ) dovute a dimenticanze da parte di programmatori poco esperti nel campo.
Per quanto le Magic Quotes possano risultare veramente utili, ci sono dei casi da tenere bene in considerazione durante lo sviluppo di soluzioni Open Source oppure in previsione di inaspettati cambi di configurazione del web server e dunque, parliamo dell'argomento Portabilita': E' bene ricorrere alla funzione get_magic_quotes_gpc() per ricavare l'attuale stato della direttiva, qualora fosse disabilitata e ricorrere successivamente alla funzione set_magic_quotes_runtime() per attivarla a runtime, ovviamente se ce ne fosse bisogno. Un altro caso e' relativo alle Prestazioni del server, sebbene non tutti i dati gestiti da Script PHP e inseriti in eventuali SQL necessitano del processo delle Magic Quotes, e' bene ricorrere alla funzione addslashes() sui singoli dati, per avere maggiore efficienza, anziche' ricorrere alla soluzione globale su tutti i dati. Un ultimo caso sarebbe quello della Incovenienza, poiche' non tutti i dati necessitano del trattamento delle Magic Quotes, risulterebbe noioso ritrovarsi risultati inaspettati, ad esempio invio di email o il salvataggio delle informazioni su file di testo con parole o frasi contenenti il carattere inaspettato "\".
Spesso l'utilizzo o meno delle direttive e' dettato da un preciso bisogno, prima di procedere a scrivere del codice e' bene accertarci del risultato che ci attendiamo, senza *imbarcarci* in problemi che effettivamente non esistono.

Prima di proseguire verso il paragrafo successivo, proporremo alcuni esempi pratici sulle Magic Quotes, come attivarle a sistema oppure scrivere del codice PHP portabile indipendente dalle configurazioni del web server:

1. Esempio della sezione Magic Quotes del file di configurazione di PHP:

codice:
; Magic quotes
;

; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = Off

; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off

; Use Sybase-style magic quotes (escape ' with '' instead of \').
magic_quotes_sybase = Off
Nel caso in cui l'accesso alla configurazione principale del PHP sul web server non fosse possibile ma si potrebbe ricorrere al file .htaccess, solitamente disponibile su web server Apache, sara' sufficiente aggiungere la direttiva che segue, al file .htaccess:
codice:
php_flag magic_quotes_gpc off
Se il file in questione non fosse disponibile e considerato che, come discusso prima, la direttiva magic_quotes_gpc non puo' essere impostata a Runtime, esiste un metodo per aggirare il problema, trattando le variabili predefinite GET, POST e COOKIE *manualmente* direttamente da codice, rendendo la stessa applicazione web portabile e dunque indipendente dalla configurazione del web server:
File: no_magic_quotes_gpc.php
Codice PHP:
<?php
// Controllo che la direttiva magic_quotes_gpc sia ON
if ( get_magic_quotes_gpc() ) {
    echo 
"La direttiva e' attiva";

    
// Funzione per rimuovere gli slash aggiunti dalla direttiva, dai singoli elementi per ogni array POST, GET e COOKIE
    
function stripslashes_deep($value) {
        
$value is_array($value) ? array_map('stripslashes_deep'$value) : stripslashes($value);
        return 
$value;
    }

    
// Rielaboro le informazioni GPC
    
$_GET array_map('stripslashes_deep'$_GET);
    
$_POST array_map('stripslashes_deep'$_POST);
    
$_COOKIE array_map('stripslashes_deep'$_COOKIE);
}

// Testing
echo "<pre>";
print_r($_GET);
echo 
"</pre>";
?>
Un test si potrebbe fare semplicemente richiamando lo script dalla barra degli indirizzi del browser impostando una variabile GET del tipo “L'albero e' verde”:
no_magic_quotes_gpc.php?myString=L'albero e' verde
Come risultato otterremo la stringa inalterata, senza i backslashes di troppo, aggiunti automaticamente dalla direttiva magic_quotes_gpc.

Filesystem

Come e' stato per i paragrafi precedenti, e' bene soffermarsi ora sugli argomenti relativi agli aspetti sulla sicurezza del Filesystem. Dal momento che i permessi in lettura e scrittura per gli script PHP sul Filesystem, sono dettati dallo stesso filesystem e quindi, PHP viene considerato come un vero e proprio utente del sistema, e' necessario assicurarsi di aver impostato le corrette regole di lettura e scrittura sui diversi file che potrebbero essere aperti e quindi letti se non addirittura scritti dagli script PHP e conseguentemente portare ad una corruzione delle informazioni presenti sul Server, ad esempio leggere file come “/etc/passwd”, appropriarsi di informazioni importanti oppure avviare diversi servizi.
In questo paragrafo verranno proposti esempi concreti sui possibili attacchi al Filesystem e diverse soluzioni per evitare furti di informazioni. Il primo esempio che andremo a considerare e' il medesimo proposto nella documentazione ufficiale del PHP: “Eliminare un file presente in una directory Utente, specificato come dato POST”:

Codice PHP:
<?php
$username 
$_POST['user_name']; // Username specificato nel POST
$userfile $_POST['user_file']; // File da eliminare specificato nel POST

$homedir "/home/$username"// Costruisco il percorso per la home dell'utente

unlink ("$homedir/$userfile"); // Rimuovo il file dell'utente

echo "$userfile e' stato eliminato !";
?>
Lo script proposto esegue una semplice operazione, accetta due dati POST, lo username ed il file dell'utente da eliminare. Per quanto lo script possa sembrare inoffensivo, potrebbe rappresentare un grave problema per il filesystem. Come descriveremo nei paragrafi succesivi, relativi alle SQL Injection, quando i nostri script trattano dati provenienti dall'esterno, come POST o GET, vale una delle regole fondamentali per lo sviluppo di semplici script o applicazioni web: “Fidarsi e' bene ma non fidarsi e' meglio”. In questo caso, nello script precedentemente proposto, un utente malintenzionato potrebbe specificare dati non inerenti alle directory o files utente e cercare di attaccare direttamente il Filesystem, ad esempio lasciando inalterato il campo Username ma variando quello relativo al file da eliminare e quindi specificare quanto segue: “../../etc/passwd”, cio' fa si' di salire di due directory e quindi ritrovarci nella directory radice del sistema “/” e successivamente salire fino ad arrivare al file “/etc/passwd”. A questo punto, supponendo che PHP avesse privilegi da root ( amministratore di sistema ), cio' comporterebbe la perdita' di uno dei file piu' importanti del sistema. Come questo, ovviamente, tanti altri casi potrebbero verficarsi se non si prendono le dovute misure di sicurezza sui dati esterni. Se non la cancellazione dei dati, per lo meno la lettura potrebbe essere possibile.
Di seguito vedremo come prevenire questo tipo di attacco al Filesystem, eseguendo opportuni controlli sui dati immessi mediante esempi concreti. Questa volta cercheremo di ricreare uno scenario molto semplice per capire meglio il concetto sulla sicurezza dei files presenti nel sistema e/o nelle directory delle nostre applicazioni web, ma prima di visualizzare script di esempio preoccupiamoci di visualizzare la struttura delle directory della nostra applicazione o sito dinamico:

/main
/main/scripts/
/main/scripts/pubblico.txt
/main/privato.txt

La directory principale della nostra applicazione e' rappresentata da “/main” mentre nella sotto-directory “/main/scripts/” saranno presenti i vari scripts PHP che proporremo piu' avanti ed avranno il compito di leggere vari files di testo. Infine troviamo il file “/main/privato.txt” rappresentera' il file di sistema protetto a cui non vi si potra' accedere dagli script PHP residenti in “/main/scripts/” mentre, il file “/main/scripts/pubblico.txt” potra' essere letto e teoricamente scritto da chiunque.
Per iniziare, proporremo lo script PHP base che fa uso delle funzioni per la gestione del Filesystem per la lettura del file pubblico: /main/scripts/pubblico.txt:

File: leggi_pubblico.php

Codice PHP:
<?php
/**
 * ESEMPIO 1
 * Lettura di un file pubblico
 */

// File da visualizzare
$myFile "pubblico.txt";

// Apro il file e lo leggo il contenuto
$handle fopen($myFile"r");
$contents fread($handlefilesize($myFile));
fclose($handle);

// Visualizzo il contenuto del file
echo $contents;
?>
Ammettendo che il file da leggere, ed in questo caso “pubblico.txt” potesse venire impostato tramite variabili GET o POST, sarebbe molto semplice, per un malintenzionato accedere al file protetto, sostituendo il nome del file pubblico con quello privato, ecco come:

File: leggi_pubblico_alterato.php

Codice PHP:
<?php
/**
 * ESEMPIO 2
 * Lettura di un file di sistema, quindi teoricamente protetto
 */

// File da visualizzare
$myFile "../privato.txt";

// Apro il file e lo visualizzo a video
$handle fopen($myFile"r");
$contents fread($handlefilesize($myFile));
fclose($handle);

// Visualizzo il contenuto del file
echo $contents;
?>
Come si nota, e' stato sufficiente cambiare il nome del file per accedere al file privato e quindi accedere ad eventuali dati sensibili. A questo punto verra' proposta una piccola ma significativa miglioria di codice per effettuare un controllo sul nome del file proposto, controlleremo la presenza di eventuali salti di directory e quindi accerteremo l'assenza di sequenze di caratteri come “../” che consentono allo script di salire di directory, ecco come:

File: leggi_pubblico_migliorato.php

Codice PHP:
<?php
/**
 * ESEMPIO 3
 * Lettura di un file di sistema, quindi teoricamente protetto
 * Aggiunta di controlli sul nome del file
 */

// File da visualizzare
$myFile "./../sistema.txt"// Cerco di agirare il controllo

// Alcuni controlli sul nome del file
if ( eregi('../'$myFile) ) {
    echo 
"Nome del file specificato non valido. Impossibile continuare";
} else {
    
// Apro il file e lo visualizzo a video
    
$handle fopen($myFile"r");
    
$contents fread($handlefilesize($myFile));
    
fclose($handle);

    
// Visualizzo il contenuto del file
    
echo $contents;
}
?>
In questo modo, potranno essere letti esclusivamente i files appartenenti alla stessa directory oppure alle sotto directory dell'applicazione web o dello script. E' sempre consigliato ricorrere ai controlli mediante le funzioni Regular Expressions, tutto cio', comporta ovviamente uno studio approfondito sull'argomento.

In questo paragrafo si e' introdotto l'argomento relativo ad alcune problematiche del filesystem, ma come queste, potrebbero presentarsene molte altre, e' necessario pensare a tutti i possibili attacchi e cosa piu' importante cercare di ridurre i rischi.

Database e SQL Injection

L'archiviazione e la gestione dei dati che vengono serviti giornalmente dai tanti servizi oggi accessibili su internet, come applicazioni o portali web avviene per la maggior parte dei casi attraverso database server ( DBMS ). Uno degli argomenti piu' importanti per chi sviluppa applicazioni web basate su Database consiste nell'evitare un' eventuale compromissione degli stessi dati situati nel database poiche', in molti casi si potrebbe trattare di dati sensibili. In questo paragrafo affronteremo gli aspetti legati ai possibili attacchi verso le nostre applicazioni e quindi, verranno illustrate varie tecniche per accedere e manipolare i dati sfruttando direttamente le falle dei nostri script; ed inoltre, studieremo le regole di base per una progettazione sicura dei nostri Database.
Oggigiorno tanti sviluppatori ignorano l'importanza ed i rischi che possono presentare le Structured Query Language ( SQL ) presumendo che queste siano comandi fidati che non potrebbero mai essere alterati dall'esterno degli stessi script e cosa piu' importante causare danni ai dati salvati nel Database, ma tutto cio' non e' vero.
La tecnica delle SQL Injection, rappresenta probabilmente l'argomento piu' importante riguardo la sicurezza e lo sviluppo di applicazioni basate sul web e non solo. Viene spesso utilizzata per alterare, visualizzare o compromettere informazioni salvate nei Database e cosa piu' pericolosa attaccare direttamente il sistema operativo del Server che ospita il DB, tutto questo tramite delle iniezioni dirette di porzioni di stringhe SQL nella query che verra' generata in modo dinamico dallo script per mezzo di variabili ottenute dall'esterno, come COOKIE, POST o GET ed infine eseguita. Piu' avanti, nell'articolo proporremo degli esempi che renderanno meglio l'idea della pericolosita' delle SQL Injection ed infine si spieghera' come prevenire questa tipologia di attacchi.
Come convenzione negli esempi proposti utilizzeremo delle variabili dichiarate localmente all'interno del codice PHP che andranno a simulare le possibili variabili d'ambiente GPC ( GET, POST o COOKIE ) proposte allo script e partiremo dal presupposto di essere gia' connessi al Database. Analizzeremo la situazione di partenza di ciascun script per poi capire i possibili exploit da utilizzare per iniettare porzioni SQL e quindi alterare il risultato finale della query ed eventualmente i dati visualizzati sulla pagina.
Introdotta la tecnica delle SQL Injection ed illustrata la convenzione che andremo ad utilizzare non resta che soffermarci sul database di prova che utilizzeremo nei nostri esempi. Prenderemo in considerazione una semplice struttura di Database per la gestione di Articoli e Utenti per un sito di informazione.

1° Esempio – Elenco degli articoli pubblicati per Utente

Originale

Codice PHP:
<?php
...

// Simulo dato _GET
$user_id "1";  // $_GET['user_id'];

$strSQL "SELECT * FROM articles WHERE article_user_id = '$user_id'";
$result mysql_query($strSQL);

while ( 
$row mysql_fetch_assoc($result) ) {
    echo 
$row['article_id'] . " - " $row['article_title'] . "<hr />";
}
?>
L'esempio sopra proposto elenchera' tutti gli articoli pubblicati dall'utente individuato dall'identificativo 1, il listato successivo visualizzera' un possibile exploit per visualizzare l'elenco completo degli articoli, pubblicati da tutti gli utenti presenti.

Exploit :

Codice PHP:
<?php
...

// Simulo dato _GET
$user_id "1' OR 1 = '1";  // $_GET['user_id'];

$strSQL "SELECT * FROM articles WHERE article_user_id = '$user_id'";
$result mysql_query($strSQL);

while ( 
$row mysql_fetch_assoc($result) ) {
    echo 
$row['article_id'] . " - " $row['article_title'] . "<hr />";
}
?>
Come si nota facilmente e' stato sufficiente iniettare all'interno della variabile contenente l'identificativo dell'utente, una porzione di stringa: “ ' OR 1 = '1 ” per far si' da alternare il risultato finale prodotto dalla query.

Seguendo questo semplice e banale esempio e' facile immaginare quali potrebbero essere i tanti rischi associati a queste tecniche, oggi conosciute come SQL Injection. Si potrebbero bypassare controlli utente, alterare dati mantenuti in un database e tanto altro ancora, per non parlare di attacchi diretti al Database Server e all'intero Sistema Operativo Host. Prevenire questa tipologia di attacco e' possibile, nei paragrafi seguenti studieremo quali sono le applicazioni piu' a rischi e quali sono i metodi per proteggersi.

Le applicazioni piu' a rischio

Generalmente la domanda che ci si pone piu' spesso e' – Quali sono le applicazioni piu' a rischio alle SQL Injection ? - Solitamente la risposta va sempre a discapito delle soluzioni Open Source, tutto cio' purtroppo e' vero. Il motivo e' del tutto semplice, avere a disposizione il codice sorgente aperto, significa essere a conoscenza delle eventuali falle e dei possibili exploit a disposizione, e cosa piu' importante, e' nota anche la struttura del database. Per chi esegue un attacco di tipo SQL Injection avere a dispozione tutte queste importanti informazioni significa essere in grado di creare nuovi attacchi di diversi livelli di pericolosita', a seconda delle varie misure di sicurezza adottate all'interno dell'applicazione. Sebbene le soluzioni piu' a rischio siano quelle Open Source e' anche vero che, “grazie” ai continui attacchi e ai famosi strumenti per la ricezione e la segnalazione di eventuali Bugs, gli sviluppatori interessati al mantenimento del progetto ( e quindi dell'applicazione ) possono fornire in tempi brevi le versioni aggiornate, sprovviste di falle. Ne consegue quindi, un continuo miglioramento dell'applicazione stessa nel tempo. Spesso, nel mondo dell' Open Source, un'applicazione ben collaudata e priva di bugs viene considerata STABLE e quindi disponibile per tutti gli utilizzatori finali che vogliono la versione realmente stabile e sicura. Al contrario per indicare le versioni in fase di sviluppo per l'introduzione di migliorie e nuove caratteristiche, viene utilizzato il termine UNSTABLE, generalmente queste versioni sono disponibili per tutti gli utenti finali, sviluppatori o utenti maliziosi che intendono rispettivamente, testarne le nuove caratteristiche e verficarne le nuove migliorie introdotte, apprendere nuovi concetti e tecniche di programmazione, trovare exploit e potenziali falle SQL Injection.

Come proteggersi dalle SQL Injection

Come si e' notato negli esempi precedenti, i rischi maggiori legati alle SQL Injection provengono da dati esterni come iniziezioni di valori POST, GET o COOKIE. Le tecniche ed i consigli da seguire per prevenire possibili attacchi SQL Injection sono riassunti in questa lista:
  • Mai fidarsi di ogni tipo di elemento HTML INPUT presente all'interno di una FORM ( modulo web ), siano essi SELECT o INPUT di tipo HIDDEN. Eseguire sempre opportuni controlli sul tipo di dato e anche sui valori provenienti da questi elementi;

  • Non avviare mai connessioni verso Database con privilegi da amministratore, bensi' creare e utilizzare una utenza con permessi specifici e azioni limitate al Database;

  • Controllare sempre che ogni valore ricevuto in Input sia del tipo aspetto; Per gestire questo tipo di controlli e' opportuno utilizzare determinate funzioni messe a dispozione dal PHP per validare il tipo di dato delle variabili: PHP: Variable Handling Functions - Manual, PHP: Character Type Functions - Manual, oppure e' consigliabile ricorrere alle funzioni Regular Expressions ( PHP: Regular Expression Functions (Perl-Compatible) - Manual );

  • Aggiungere i carattere di escape “\” per qualsiasi valore non numerico specificato nelle SQL. Utilizzare le funzioni specifiche per i relativi DBMS ( per MySQL, vedesi PHP: mysql_escape_string - Manual ). In caso contrario, se non sono disponibili funzioni specifiche e' consigliabile ricorrere alle alternative come addslashes() ( PHP: addslashes - Manual ) e str_replace() ( PHP: str_replace - Manual );

  • Non mostrare a video alcuna informazione relativa alla struttura del Database.
Oltre a questi suggerimenti sarebbe opportuno, ove possibile, abilitare e gestire il Log interno del DBMS, cosi' da visualizzare le singole operazioni eseguite sui Database e se necessario, sistemare eventuali problemi di Injection sulle query.

Una progettazione sicura del Database

Generalmente quando si crea un database, ad esso viene associato un utente proprietario, che il piu' delle volte e' lo stesso utente che ha eseguito il comando per la creazione del DB oppure sara' lo stesso Amministratore ( il cosidetto superuser ). Questi due utenti dispongono di permessi amministrativi riguardo la struttura del database, di conseguenza sono in grado di alterare la struttura stessa, aggiungendo nuovi campi, cancellandone altri oppure rimuovere completamente delle tabelle, in alternativa, crearne delle nuove. Per motivi di sicurezza quindi, e' bene non avviare mai connessioni verso il database specificando come username lo stesso creatore oppure il superuser, bensi' specificare un utente creato ad-hoc con permessi limitati e specifici ( solo lettura e scrittura di dati ) sul database, se non del tutto, sulle singole tabelle.
Per rafforzare la sicurezza all'interno delle applicazioni, potrebbe essere utile creare piu' utenti con permessi differenti, in base alle necessita' richieste dalle diverse aree dell'applicazione stessa. In questo modo, ammettendo per assurdo che qualche maleintenzionato possa violare i sistemi di sicurezza e quindi rubare l'identita' per l'accesso all'applicazione, sara' in grado di operare esclusivamente con i permessi concessi all'utente del database precedentemente assegnato per quella determinata area dell'applicazione. Sebbene il sistema di sicurezza e' stato violato, e' anche vero che i danni sono limitati.

Error Reporting

La fase di debugging e di testing rappresentano i passaggi piu' importanti per quanto concerne la sicurezza delle applicazioni web. E' necessario soffermarsi e dedicare molto tempo durante queste fasi per garantire almeno, al primo momento, la sicurezza “massima” dell'applicazione al rilascio della prima versione. Ma ovviamente non possiamo certo garantirne la sicurezza assoluta, exploits o bugs di varia natura potrebbero sorgere in qualsiasi momento.
Prevenire eventuali bugs o malfunzionamenti e' possibile farlo tramite le funzioni PHP, dedite al report degli errori ( error_reporting() ).
Le tecniche di “error reporting” rappresentano un utile strumento durante le fasi di “test” e di “debug” dei nostri scripts, in qualsiasi momento potremo essere a conoscenza di eventali malfunzionamenti del codice. Comunque, nella fase di “produzione” e quindi, al rilascio di eventuali versioni stabili destinate agli utenti finali e quindi, potenzialmente esposte a vari tipi di attacco, e' sempre una buona norma disabilitare ogni tipo di “error reporting”, sia esso gestito da PHP che da sistemi sviluppati “ad-hoc” all'interno del codice.
Un utente malizioso, in cerca di utili informazioni sul funzionamento di determinati scripts, potrebbe facilmente repererile dai messaggi di errore generati da PHP. Nomi di variabili, informazioni sulla struttura di Database ed altro ancora sono tutte informazioni che non devono essere rese pubbliche, in nessuna circostanza nella fase di “produzione”.
Il PHP, come spiegato in precedenza, fornisce utili strumenti per il report degli errori e logging, la funzione “error_reporting()” ( PHP: error_reporting - Manual ) ad esempio, in base a determinate impostazioni definite a runtime dallo stesso utente oppure dal file di configurazione PHP.INI, abilitera' o disabilitera' la visualizzazione di vari tipi di messaggi di errore in caso si verificasse un malfunzionamento nel codice, di qualsiasi genere. E' utile sapere che e' consentito impostare anche il tipo di messaggi di errore da visualizzare, che vengono suddivisi in categorie ben precise. Di seguito verra' proposto un semplice codice di esempio sul funzionamento dell'error reporting e una tabella riepilogativa dei vari messaggi di errori attivabili:

Codice PHP:
<?php 
/* Disabilito visualizzazione degli errori 
 * Si potrebbe ricorrere agli operatori bitwise,
 * in questo caso per disabilitare la visualizzazione degli errori
 * avremmo potuto passare questo parametro ~E_ALL
 */
error_reporting(0); // error_reporting(~E_ALL);

// Associo ad una variabile il valore di una costante non definita 
$myVar CIAO

// Visualizzo il contenuto di $myVar 
echo $myVar
?>
Generalmente il seguente codice, con l'error_reporting abilitato, dovrebbe restituire il solito messaggio di errore:

Quote:
Notice: Use of undefined constant CIAO ...
Ma non in questo caso, poiche' la visualizzazione degli errori e' stata completamente disabilitata dalla riga: “error_reporting(0);”. La funzione error_reporting accetta come argomento valori numerici interi a cui, per ciascun numero e' associata la tipologia di errore da visualizzare. Oltre ai valori numerici e' possibile ricorrere a delle costanti predefinite del PHP, a cui e' associato il rispettivo valore numerico per la segnalazione degli errori. Cosi' facendo, lo sviluppatore stesso offrira' del codice di facile interpretazione ed inoltre verranno risolti i tanti problemi relativi al porting dello stesso codice con versioni di interpreti PHP differenti. Capita spesso che, differenti versioni di PHP abbiano diversi valori numerici per individuare le diverse classi di errori. E' quindi consigliabile fare sempre uso delle costanti predefinite di cui, di seguito viene visualizzata la lista completa aggiornata al PHP 5.2.x:
  • E_ERROR ( valore 1 ): Fatal run-time errors. These indicate errors that can not be recovered from, such as a memory allocation problem. Execution of the script is halted.

  • E_WARNING ( valore 2 ): Run-time warnings (non-fatal errors). Execution of the script is not halted.

  • E_PARSE ( valore 4 ): Compile-time parse errors. Parse errors should only be generated by the parser.

  • E_NOTICE ( valore 8 ): Run-time notices. Indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script.

  • E_CORE_ERROR ( valore 16 ): Fatal errors that occur during PHP's initial startup. This is like an E_ERROR, except it is generated by the core of PHP.

  • E_CORE_WARNING ( valore 32 ): Warnings (non-fatal errors) that occur during PHP's initial startup. This is like an E_WARNING, except it is generated by the core of PHP.

  • E_COMPILE_ERROR ( valore 64 ): Fatal compile-time errors. This is like an E_ERROR, except it is generated by the Zend Scripting Engine.

  • E_COMPILE_WARNING ( valore 128 ): Compile-time warnings (non-fatal errors). This is like an E_WARNING, except it is generated by the Zend Scripting Engine.

  • E_USER_ERROR ( valore 256 ): ser-generated error message. This is like an E_ERROR, except it is generated in PHP code by using the PHP function trigger_error().

  • E_USER_WARNING ( valore 512 ): User-generated warning message. This is like an E_WARNING, except it is generated in PHP code by using the PHP function trigger_error().

  • E_USER_NOTICE ( valore 1024 ): User-generated notice message. This is like an E_NOTICE, except it is generated in PHP code by using the PHP function trigger_error().

  • E_STRICT ( valore 2048 ): Run-time notices. Enable to have PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code.

  • E_RECOVERABLE_ERROR ( valore 4096 ): Catchable fatal error. It indicates that a probably dangerous error occured, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handle (see also set_error_handler()), the application aborts as it was an E_ERROR.

  • E_ALL ( valore 8191 ): All errors and warnings, as supported, except of level E_STRICT in PHP < 6.
Per maggiori informazioni relative alla gestione degli errori e il sistema di log di PHP, e' bene consultare la documentazione ufficiale disponibile in rete: PHP: Error Handling and Logging Functions - Manual

Prevenire attacchi SPAM

Un'ulteriore e significativa problematica da considerare nello sviluppo di applicazioni web, portali o piccoli script che prevedono moduli pubblici, liberi di essere compilati ed inviati da chiunque – vedesi moduli web per i contatti, guestbook, commenti ed altro ancora - consiste nell'accertarsi della validita' delle informazioni inviate dall' “utente”.
Come possiamo accertarci che i dati inviati soddisfano a pieno i requisiti richiesti dalla nostra applicazione, quindi che siano stati inviati da una reale persona fisica e non siano semplicemente dati falsati generati da sistemi automatici ( bot ) per produrre dello Spam e/o Compromissione dei dati da gestire ? In questo paragrafo verra' illustrata una delle migliori tecniche per prevenire questo genere di attacchi mediante una specifica Classe PHP 5, denominata “Check Spam” che provvedera' a gestire la creazione del codice di sicurezza CAPTCHA e il successivo controllo.
Per chi non fosse a conoscenza del significato del termine CAPTCHA ( acronimo di: “completely automated public Turing test to tell computers and humans apart” ) e' bene soffermarsi sull'argomento. Come viene suggerito dall'acronimo stesso, CAPTCHA indica un test di Turing pubblico e completamente automatizzato per distinguere Umani da Computer ( nel nostro caso, i bot ). Generalmente si puo' ricorrere al CAPTCHA tramite diverse soluzioni, ad esempio: domande a risposta multipla, quesiti matematici oppure codici di sicurezza poco leggibili dall'occhio umano. Tramite queste tecniche potremo facilmente accertarci che l'utilizzatore del nostro “sistema” e' un umano e non un altro computer.
Nel nostro esempio, come accennato precedentemente sfrutteremo l'ultima tecnica, ovvero la generazione di un codice di sicurezza poco leggibile dall'occhio umano e difficilmente comprensibile da sistemi OCR ( Optical Character Recognition ). Poiche' generare un codice di sicurezza non significa affatto che non sara' riconosciuto da sistemi automatici, quindi e' bene utilizzare sistemi CAPTCHA ben collaudati, stabili e sicuri come “Check Spam” ( PHP Classes - Class: Check spam ) che allo stato attuale risulta essere la migliore soluzione “anti-spam” disponibile su PHPClasses.org per la categoria PHP 5 e inoltre viene rilasciata sotto GPL ( General Public License ), per il corretto funzionamento di questa classe e' richiesta la libreria grafica GD con il supporto PNG.
Nei vari esempi che proporremo verra' considerato lo scenario di un semplice script “Guestbook” ( un tradizionale libro degli ospiti ) che fa uso di un file di testo per la memorizzazione dei vari commenti lasciati da vari utenti. Lo script verra' realizzato in diversi passaggi, inizieremo a scrivere e commentare le versioni di script generalmente piu' comuni e piu' veloci da sviluppare e sicuramente meno sicuri, per terminare con una versione stabile, sicura e priva di eventuali exploit per capire a fondo le diverse procedure da seguire per sviluppare moduli web in tutta sicurezza.
La prima fase di sviluppo del nostro modulo Guestbook prevede una serie di controlli per validare i dati inviati ed il modulo HTML da complilare. Il codice e' commentato e non necessita' di ulteriori note aggiuntive:

File: gb_form.php ( codice completo )

Codice PHP:
<?php 
/** 
 * Guestbook - Modulo per inserimento dati 
 */ 

// Controllo presenza dati _POST 
if ( count($_POST) ) { 
    
// Alcuni controlli sui dati 
    
if ( ereg("^[0-9a-z\._-]+@[0-9a-z\_-]+\.([a-z]+\.)?[a-z]{2,3}$"$_POST['gb_email']) ) { // E-Mail 
        
if ( strlen($_POST['gb_messaggio']) ) { // Messaggio 
            // Scrivo il file guestbook.txt 
            
$handle fopen("guestbook.txt""a+"); 
            
$contenuto date("Y-m-d H:i:s") . "\t" $_POST['gb_email'] . "\t"
            
$contenuto .= ( get_magic_quotes_gpc() ) ? stripslashes($_POST['gb_messaggio']) : $_POST['gb_messaggio']; 
            
$contenuto .= "\n"
             
            
fwrite($handle$contenuto); 
             
            
fclose($handle); 
        } 
    } 

?> 
<html> 
    <head> 
        <title>Guestbook - Modulo inserimento dati</title> 
    </head> 
    <body> 
        <h1>Inserisci nuovo commento</h1> 
        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>"> 
            Tua E-Mail:<br /> 
            <input type="text" name="gb_email" size="50" /><br /> 
            Messaggio:<br /> 
            <input type="text" name="gb_messaggio" size="50"><br /> 
            <input type="submit" value="invia commento" /> 
        </form> 
    </body> 
</html>
Sebbene il codice sopra proposto possa apparire “sicuro”, non lo e'. Sono stati inseriti gli opportuni controlli sui dati inviati, ma un controllo CAPTCHA non risulta da nessuna parte e di conseguenza, il nostro script potrebbe essere potenzialmente esposto ad attacchi SPAM per mezzo di sistemi automatici, ma come ?
Una delle tecniche piu' utilizzate dai vari “spammers automatici” consiste nell'utilizzo di librerie e/o funzioni specifiche per la connessione e la comunicazione verso diversi server e diversi protocolli, ad esempio HTTP, come nel nostro caso.
Nel prossimo esempio studieremo uno script PHP che facendo uso della libreria cURL ( Client URL: PHP: CURL, Client URL Library Functions - Manual ) consente di avviare questo genere di attacchi. E' opportuno considerare che queste librerie vengono utilizzate anche per scopi “benevoli” nella programmazione, e non certo per generare esclusivamente attacchi e deturpare sistemi informatici.
Lo script che segue e' abbastanza semplice da studiare, nelle prime righe di codice verra' inizializzata la connessione per l'host remoto ( curl_init() ) nelle righe successive verranno impostate diverse opzioni per avviare una comunicazione di tipo HTTP POST e specificando quali dati inviare, ed infine eseguiremo realmente la comunicazione ( per 3 volte ):

File: gb_curl_attack.php

Codice PHP:
<?php 
/** 
 * Invio di informazioni al modulo gb_form.php tramite CURL 
 * Simulazione BOT SPAM 
 */ 
 
// Avvio una connessione verso il modulo da attaccare 
$curl curl_init("http://mydomain.ext/modulo_web/gb_form.php"); 

// Imposto le opzioni per il trasferimento di dati HTTP POST 
curl_setopt($curlCURLOPT_RETURNTRANSFERtrue); 
curl_setopt($curlCURLOPT_POSTtrue); 
curl_setopt($curlCURLOPT_POSTFIELDS"gb_email=attacker@spammer.com&gb_messaggio=Messaggio spam"); 

// Eseguo la comunicazione per 3 volte 
for ($i 0$i 3$i++) { 
    
curl_exec($curl); 


// Libero le risorse di memoria occupate 
curl_close($curl); 
?>
Eseguendo lo script proposto saranno eseguite 3 comunicazioni, complete di tutte le informazioni valide necessarie verso il modulo web precedentemente sviluppato. Capire quali informazioni inviare e' molto semplice, e' sufficiente dare uno sguardo al codice HTML del modulo web e prendere nota del nome dei vari campi e dei valori accettati.
Le tecniche per prevenire questo genere di attacchi, sono molteplici e variano a seconda della situazione in cui ci troviamo, ad esempio, si potrebbe ricorrere all'uso delle Sessioni, in questo caso, introducendo un opportuno controllo su una determinata sessione settata, possiamo facilmente dedurre se il modulo e' stato complilato da un “utente umano” o da un “sistema automatico”, ma tutto questo non sara' oggetto di studio in questo tutorial.
Miglioriamo invece, il modulo web, con un controllo di tipo CAPTCHA introducendo l'uso della classe “Check Spam”. Una volta che abbiamo scaricato il pacchetto completo della classe menzionata sara' sufficiente copiare e incollare tutta la directory “checkspam_x.y” ( x e y indicano il numero della versione ) all'interno della directory radice del nostro script, seguire le semplici istruzioni sul funzionamento e aggiornare lo script del modulo web.
Di seguito viene mostrato il codice PHP dello script “gb_form.php” aggiornato e reso piu' sicuro tramite l'introduzione del controllo CAPTCHA:

File: gb_form.php ( aggiornato per il controllo CAPTCHA Check Spam )

Codice PHP:
<?php 
/** 
 * Guestbook - Modulo per inserimento dati 
 * Versione modificata per prevenire attacchi spam, tramite la classe Check Spam 
 */ 

// Richiamo la classe Check Spam 
define('CHECKSPAM_DIR','checkspam_x.y/checkspam/'); // <- Da modificare
require_once(CHECKSPAM_DIR.'checkspam.class.php'); 

// Avvio una nuova sessione Check Spam 
$cs = &new checkspam
$cs->init_session(); 

// Controllo presenza dati _POST 
if ( count($_POST) ) { 
    
// Controllo codice CAPTCHA 
    
if ( $cs->verify($_POST['secretcode']) ) { 
        
// Alcuni controlli sui dati 
        
if ( ereg("^[0-9a-z\._-]+@[0-9a-z\_-]+\.([a-z]+\.)?[a-z]{2,3}$"$_POST['gb_email']) ) { // E-Mail 
            
if ( strlen($_POST['gb_messaggio']) ) { // Messaggio 
                // Scrivo il file guestbook.txt 
                
$handle fopen("guestbook.txt""a+"); 
                
$contenuto date("Y-m-d H:i:s") . "\t" $_POST['gb_email'] . "\t"
                
$contenuto .= ( get_magic_quotes_gpc() ) ? stripslashes($_POST['gb_messaggio']) : $_POST['gb_messaggio']; 
                
$contenuto .= "\n"
                 
                
fwrite($handle$contenuto); 
                 
                
fclose($handle); 
            } 
        } 
    } 


// Generazione codice CAPTCHA 
$cs->exec_checkspam(); 
?> 
<html> 
    <head> 
        <title>Guestbook - Modulo inserimento dati</title> 
    </head> 
    <body> 
        <h1>Inserisci nuovo commento</h1> 
        <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>"> 
            Tua E-Mail:<br /> 
            <input type="text" name="gb_email" size="50" /><br /> 
            Messaggio:<br /> 
            <input type="text" name="gb_messaggio" size="50"><br /> 
            Codice di sicurezza:<br /> 
            <?php $cs->print_imagetext(); $cs->print_input(); ?><br /> 
            <input type="submit" value="invia commento" /> 
        </form> 
    </body> 
</html>
La versione aggiornata non sara' piu' vulnerabili a tipi di attacco SPAM.

Difenderci dal Cross Site Scripting ( XSS )

Il Cross-site scripting ( abbreviato in XSS o CSS ) e' un genere di falla riscontrabile in tutte quelle applicazioni web che permettono il code-injection (iniezione di codice) nelle pagine visualizzate da altri utenti. Il codice iniettato si compone generalmente di HTML e script client-side Javascript. Una falla che permette il cross-site scripting puo' essere usata da utenti malintenzionati per bypassare controlli d'accesso ed ottenere dati sensibili.
Recentemente, vulnerabilita' di questo tipo sono state usate per creare pagine dedicate al phishing ed exploit verso determinati browser.

Quando Netscape introdusse il linguaggio Javascript nel suo browser, furono chiari i rischi insiti nel permettere ad un server web di inviare codice eseguibile al browser. Il problema principale si presentava quando l'utente aveva piu' di una finestra del browser aperta. In alcuni casi, uno script proveniente da una pagina poteva avere accesso ai dati presenti in un'altra pagina o oggetto. Questo comportamento doveva essere bloccato, visto che un utente malintenzionato potrebbe in questo modo cercare di carpire informazioni sensibili.
Per poter aggirare il problema, i browser introdussero la cosiddetta "same origin policy" (politica della stessa origine). Questo accorgimento permette le interazioni esclusivamente tra pagine originate dallo stesso dominio, sullo stesso protocollo e sulla stessa porta. In questo modo, un sito web malevolo non avrebbe avuto accesso a dati presenti in un'altra finestra attraverso Javascript.

Da allora sono state introdotte numerose altre politiche di controllo da parte dei browser e dei linguaggi di scripting per proteggersi da questo genere di problematiche. Parlando in generale, una falla che permette il cross site scripting e' essenzialmente una vulnerabilita' presente in una pagina web che permette di aggirare i normali meccanismi di controllo. Trovando sistemi astuti per iniettare script malevoli nelle pagine servite da un certo dominio, un malintenzionato puo' ottenere diritti d'accesso elevati a pagine contenenti dati sensibili, cookie di sessione ed una larga varieta' di oggetti teoricamente protetti.

Suddivideremo le falle di XSS in tre tipi distinti, che chiameremo per comodita' tipo 0,1 e 2. Le falle che piu' da vicino riguardano PHP sono quelle di tipo 1 e 2. In tutti i casi si tratta di pagine generate in maniera incauta, in cui gli input provenienti dall'esterno non vengono accuratamente vagliati e filtrati. Porre una certa attenzione nel parsing dei parametri che arrivano in GET e POST previene la maggior parte dei problemi e rende il sito abbastanza sicuro (di totalmente sicuro non esiste nulla) con poco lavoro. In particolare e' necessario prestare grande attenzione alla validazione di input provenienti dagli utenti che poi verrano usati nelle pagine (o nelle mail) generate.

Tipo 0

Questa forma di XSS viene chiamata anche DOM-based o locale. Nella falla di tipo 0, il problema risiede nella parte di script client-side della pagina stessa. Per esempio, se un pezzo di codice Javascript accede ad i parametri GET ed usa queste informazioni per scrivere qualcosa sulla pagina (e questa informazione non e' filtrata in alcun modo), ci troviamo davanti ad una grave falla. L'informazione verra' stampata direttamente nella pagina come codice HTML, che potrebbe contenere script aggiuntivi se la richiesta viene malformata.
Sfruttare questa falla e' molto simile allo sfruttare le falle di Tipo 1 (vedi sotto), eccetto che per una situazione importante. Per il modo in cui Internet Explorer tratta gli script client-side nelle pagine locali (ad esempio sull'hard disk di un client), una falla XSS di questo tipo si puo' risolvere nell'esecuzione remota di codice sulla macchina dell'utente.
Se un sito malevolo, ad esempio, contiene un link verso una pagina vulnerabile che, in qualche modo, e' stata installata sul sistema locale di un client, puo' iniettare in essa uno script che girerebbe con i privilegi della macchina in cui viene scaricato. Questo aggira completamente ogni tipo di controllo client-side anche lato browser, non solamente le restrizioni cross-domain che vengono normalmente aggirate da altre tecniche XSS. Il fatto che la pagina debba essere installata localmente nel computer vittima, rende la falla di tipo 0 meno pericolosa delle altre, visto che e' necessario indurre in qualche modo la vittima ad effettuare questa operazione.

Tipo 1

Questo tipo di falla viene detta anche Non-persistente o Riflessiva, ed e' il tipo piu' comune di falla XSS. Questo tipo di falla si presenta quando i dati provenienti da un client web vengono usati da script server-side per generare una pagina per l'utente (e' il caso di PHP se i dati provenienti in GET o POST non vengono controllati).
Se i dati provenienti dal client vengono utilizzati nella pagina risultante senza controlli, sara' possibile iniettare uno script nella pagina generata dal server. Un esempio classico si puo' trovare nelle pagine di ricerca: Spesso la stringa viene replicata nella pagina risultato per sottolineare cosa si sta cercando, o comunque i termini di ricerca saranno inclusi nuovamente in una text box per permettere l'editing. Se si ricerca una stringa che contiene caratteri speciali HTML e le occorrenze dei termini di ricerca non vengono accuratamente filtrate (con htmlentities ad esempio) ne risultera' una falla XSS di Tipo 1. Qualsiasi utente potra' iniettare codice e vederselo eseguire nella pagina risultante.
Questo potrebbe non sembrare un problema serio, visto che gli utenti sono in grado di iniettare codice solo nelle loro pagine. Con un po' di social engineering comunque, un utente malintenzionato potrebbe convincere la vittima a seguire un link malevolo che inserisce codice nella sua pagina risultato, dando nel frattempo al malintenzionato il pieno accesso ai dati contenuti nella pagina.
Visto che e' necessario del social engineering, molti programmatori non ritengono importante questa falla e spesso non provvedono ad arginarla. Questa mancanza viene applicata spesso alle falle XSS in generale e spesso si risolve in una corsa ai ripari quando il danno avviene (e presto o tardi in genere succedera').

Tipo 2

Questo tipo di falla XSS viene chiamata anche Persistente o di Secondo Grado, e permette la forma peggiore di attacco. Una falla di tipo 2 esiste quando i dati inviati al server vengono salvati in qualche forma ( in un database, nel filesystem del server o in altra locazione ), e quindi mostrati in una pagina web senza essere filtrati. Un esempio classico sono i forum e le bacheche elettroniche, in cui i post degli utenti vengono salvati generalmente in un DB e possono essere riletti da un gran numero di altre persone.
Queste falle sono molto piu' pericolose perché il malintenzionato deve iniettare il codice una sola volta. Cio' che inietta ha la capacita' di colpire un gran numero di utenti senza necessita' di social engineering. In casi estremi, l'intero server puo' diventare un veicolo per un cosiddetto virus XSS ( un tipo di virus che sfrutta le falle XSS per diffondersi ).
I metodi di iniezione variano enormemente, ed il malintenzionato puo' non aver nemmeno bisogno di accedere alla web application per sfruttarne la falla. Qualsiasi dato ricevuto dal server che puo' essere controllato da un utente malevolo, andra' accuratamente filtrato prima di essere mostrato in una pagina dinamica, altrimenti puo' nascere una falla di questo tipo.

In tutti e tre i casi, come detto, la falla si presenta quando nel creare una pagina non si effettua un filtro dei dati provenienti dall'esterno, almeno su quegli elementi che verranno usati per scrivere direttamente sulla pagina risultante.
Osserviamo adesso un breve esempio di codice PHP che non pone l'attenzione verso XSS e puo' risultare soggetto ad attacchi:

Esempio

Il codice seguente e' soggetto a falle di tipo 0 ed 1. Immaginate di accedere via browser a hello.php?username=PIPPO<SCRIPT>alert('vulnerabile ');</SCRIPT>
Passano al browser la stringa in questione dovrebbe far apparire una finestra con la scritta "vulnerabile". L'esempio e' banale, ma uno script costruito attentamente puo' provocare diversi problemi.

Codice PHP:
// hello.php vulnerabile
<?php
   $username
=$_GET['username'];
   echo 
"Benvenuto ".$username;
?>
Una versione corretta del precedente potrebbe essere:

Codice PHP:
// hello.php
<?php
   $username
=htmlentities($_GET['username']);
   echo 
"Benvenuto ".$username;
?>
La htmlentities() trasforma i tag HTML in elementi innocui e trasforma il codice malevolo quindi in una semplice stringa uguale a qualsiasi altra.
Attenzione a non dare per scontato il fatto che la stringa contenente codice HTML sia sempre facilmente visibile (<SCRIPT>). Lo stesso identico url piu' sopra puo' essere codificato facilmente in un piu' sibillino:

codice:
hello.php?username=PIPPO%3C%53%43%52%49%50%54%3E%61%6C%65%72%74%28%27%76%75%6C%6E%65%72%61%62%69%6C%65%27%29%3B%3C%2F%53%43%52%49%50%54%3E
Lo script vulnerabile potrebbe essere usato in un attacco persuadendo la vittima ad accedere a hello.php?<codice_malevolo>. Il codice malevolo potrebbe, ad esempio, inviare i dati di login ad un server o alla mail del malintenzionato (il tutto ovviamente all'insaputa dell'utente). Non e' difficile immaginare cosa puo' succedere se un link ad una pagina vulnerabile viene postato su di un forum e viene reso visibile a tutti gli utenti, magari con un messaggio che invoglia a visitarlo ("Ricontrolla qui i parametri del tuo account su hotmail!" se, per assurdo - ma nemmeno piu' di tanto - il server di hotmail avesse una falla XSS).

Di seguito illustriamo alcuni semplici scenari di attacco dei tre tipi menzionati. Sono situazioni tipiche avvenute spesso e volentieri, a volte anche a siti insospettabilmente prestigiosi. Utilizziamo dei nomi fittizi (inventati di sana pianta - ogni riferimento a fatti e persone esistenti e' pura fantasia) per meglio identificare le parti in causa.
In tutti gli scenari, Matteo sara' il malintenzionato, Mirko sara' l'utente ignaro del pericolo e Giuseppe il proprietario di un sito che contiene una falla XSS

Attacco di tipo 0:
  1. Matteo invia a Mirko (via email o altri meccanismi) il link verso una pagina malevola(A), appositamente costruita;

  2. Mirko clicca sul link;

  3. Il Javascript presente in (A) apre una pagina HTML vulnerabile (B), che e' installata localmente sul computer di Mirko;

  4. Nella pagina (B) viene iniettato, dalla pagina (A), del codice Javascript che si esegue in locale sul computer di Mirko;

  5. La pagina (A) di Matteo e' in grado di eseguire comandi, con i privilegi di Mirko, sulla sua macchina.
Come si puo' notare, la pagina (B) deve essere presente in qualche modo sulla macchina di Mirko, e lo stesso deve essere convinto a visitare la pagina (A). Per questo motivo non e' un attacco molto consueto, ma per ogni utente esperto che mai si farebbe infagottare in questa maniera, ne esistono svariate migliaia di altri che non hanno la minima idea che una cosa di questo genere sia possibile.

Attacco di tipo 1
  1. Mirko visita spesso un sito particolare, di proprieta' di Giuseppe. Il sito di Giuseppe permette a Mirko di effettuare il login con un username ed una password e contiene informazioni sensibili, come il numero della sua carta di credito;

  2. Matteo nota che il sito di Giuseppe contiene una falla XSS di tipo 1;

  3. Matteo crea un URL che sfrutta la falla, ed invia a Mirko una mail facendosi passare per Giuseppe (si dice in questo caso che l'email e' "spoofed");

  4. Mirko visita l'URL inviato da Matteo mentre e' connesso al sito di Giuseppe;

  5. Lo script malevolo inserito nell'URL si esegue nel browser di Mirko, come se provenisse dal server di Giuseppe. Lo script ruba le informazioni sensibili e le invia al server privato di Matteo senza che Mirko si accorga di nulla.
Anche in questo caso l'utente va in qualche modo convinto a seguire l'URL. Questo tipo di attacchi puo' essere facilmente utilizzato ai fini del phishing. In generale nel phishing non si sfruttano falle XSS (semplicemente si spedisce la vittima su un sito "fotocopia" dell'originale), ma se fosse presente una falla XSS, diciamo, nel sito della vostra banca, una email malevola potrebbe mandarvi un link per farvi accedere alla pagina vulnerabile e carpire i vostri dati.

Attacco di tipo 2
  1. Giuseppe possiede un sito web che permette agli utenti di postare messaggi ed altri contenuti, leggibili da tutti gli altri utenti del sito;

  2. Matteo nota che il sito di Giuseppe e' vulnerabile ad attacchi di tipo 2;

  3. Matteo posta un messaggio, di natura controversa, che puo' incoraggiare altri utenti a leggerlo;

  4. Semplicemente visualizzando il messaggio, i cookie di sessione degli utenti o altre credenziali possono essere catturati ed inviati al server privato di Matteo a loro insaputa;

  5. In seguito Matteo si connette con le credenziali di un altro utente e posta messaggi al loro posto. Se riesce a "buggerare" in questo modo anche l'amministratore, guadagna privilegi di accesso massimi su tutto il sito.
Questa falla delle tre e' certamente la piu' pericolosa. I sistemi piu' importanti (compreso il forum su cui state leggendo questo articolo - non temete) sono generalmente al riparo da questo genere di attacchi, anche in virtu' del fatto che le nuove falle scoperte vengono velocemente patchate. E'pero' importante, per un webmaster, tenere il proprio forum o il proprio sito dinamico costantemente aggiornato e "prevenire prima di curare", analizzando e controllando accuratamente tutti i possibili punti d'accesso per un attacco di tipo 2.

In conclusione, uno sviluppatore attento alla sicurezza provvedera' a controllare tutti i possibili punti d'accesso ( in sostanza i parametri GET e POST ) al suo sito e filtrera' in maniera accurata tutto il testo che puo' provenire dagli utenti.
Un modo veloce per verificare se esista una falla puo' essere quello di utilizzare il codice <SCRIPT>alert('falla')</SCRIPT> che ho proposto piu' sopra inserendolo un po'dovunque sia possibile (campi delle form, parametri in entrata sull'url). La comparsa di un messaggio a video implica la presenza di una falla XSS.
NB: I browser piu' recenti sono dotati di sistemi che impediscono l'XSS (almeno fino ad un certo livello). Se si vuole testare la vulnerabilita' sara' necessario disabilitare temporaneamente tali sistemi (voi magari avete IE7 o l'estensione NoSCript per Mozilla, ma non e' detto che il sito non lo visiti un utente dotato di IE4).

Conclusioni

Nel tutorial appena letto si sono apprese diverse nozioni di sicurezza sullo sviluppo di applicazioni web, scritte in PHP. Rimane da aggiungere che attualmente, il PHP rientra tra i linguaggi di scripting lato server piu' potenti e versatili, una nota importante da tenere in considerazione e' ignorare i commenti negativi che spesso si leggono e sentiamo ripetere riguardo la poca sicurezza della applicazioni scritte in PHP, specialmente le soluzioni Open Source poiche' la “sicurezza” dell'applicazione non e' data dal linguaggio di programmazione utilizzato bensi' dai canoni di sicurezza adottati dagli sviluppatori di software. PHP mette a disposizione dello sviluppatore diverse tecniche per garantire la sicurezza, in questo tutorial ne abbiamo considerate alcune ma e' bene approfondire l'argomento e tenersi sempre aggiornati su quest'ultimo e cosa piu' importante, se sfruttiamo soluzioni Open Source per i nostri lavori, accertiamoci di aggiornarli ogni volta che si propone una versione aggiornata stabile e priva di exploits o bugs.
Per concludere, oltre ai vari riferimenti proposti durante il tutorial, cerchero' di riassumere le diverse risorse sulla sicurezza, sparse per la grande rete:

PHP: Security - Manual
Main Page - SecurePHP
PHP Security Consortium
Essential PHP Security by Chris Shiflett
the Month of PHP Bugs
PHP Security Mistakes

Buona programmazione !


Ultima modifica di Master85 : 14-09-2007 a 16:33.
Master85 non è in linea   Bookmark and Share Rispondi quotando
Rispondi

Strumenti della discussione
Modalità di visualizzazione

Regole d'invio
Non puoi inserire discussioni
Non puoi inserire repliche
Non puoi inserire allegati
Non puoi modificare i tuoi messaggi

BB code è attivo
Le smilies sono attive
Il codice IMG è attivo
il codice HTML è disattivato
Trackbacks are attivo
Pingbacks are attivo
Refbacks are disattivato

Salto del forum


Tutti gli orari sono GMT +1. Attualmente sono le 23:06.


Powered by vBulletin versione 3.8.0
Copyright © 2000 - 2010, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO 3.2.0

Valid XHTML 1.0 Transitional  Creative Commons License

Eccetto dove diversamente specificato, i contenuti pubblicati in questa comunità sono rilasciati sotto Licenza
Creative Commons Attribuzione-Non commerciale-Condividi allo stesso modo 2.5 Italia License.
La comunita' di MasterDrive.it non e' responsabile di eventuali imprecisioni presenti nelle pagine.