Thread obsoleto Guida Sicurezza Del PHP

BlackDevil

Utente Medio
Autore del topic
29 Novembre 2007
126
11
Miglior risposta
0
Bene ho avuto molte richieste di come si usasse il PHP e tutte le sue funzioni, ora cercherò di farvelo capire con una guida ben dettagliata anche per persone inesperte. :emoji_slight_smile:

1) INTRODUZIONE:

Benvenuti All'introduzione del PHP.
Con questa guida intendo fornire un contributo su alcune questioni legate alla sicurezza nello scrivere codice PHP e tecnologie correlate, riferendomi sia a semplici siti Web sia a vere e proprie applicazioni "over-HTTP", di moda e sempre in aumento in quanto a numeri ed importanza.

Creare applicazioni Web based è un arduo compito anche per il più esperto programmatore: da un lato abbiamo la programmazione in senso stretto - già di per sé poco agevole, in special modo perché si ha a che fare con miriadi di tecnologie e programmi diversi, uniti ed amalgamati forse solamente dall'aderenza alle specifiche del protocollo HTTP - e dall'altro lato molti simpatici "personaggi" il cui unico scopo nella vita è di "bucare" ciò che noi ritenevamo, ovviamente a torto, inviolabile.

Più i dati ed i documenti gestiti dalla nostra applicazione hanno rilevanza, più essa verrà bersagliata da tentativi di attacco degli hacker - o, più propriamente, anche se sembra di parlar d'altro - dei "cracker".

Di più: le applicazioni Web based sono particolarmente soggette e deboli verso molti attacchi per la semplice ragione che il Web e tutta la rete Internet stessa sono nati come strumenti per lo scambio di informazioni tra utenti fidati, senza particolari meccanismi di protezione. Secondariamente, per sua definizione, un'applicazione Web è accessibile da un bacino d'utenza elevato, ivi compresi cracker e "lamer".

Nel seguito tenterò di infondere le basi di una programmazione "sicura", in maniera pratica ed essenziale, delegando ovviamente ogni lettore interessato al relativo approfondimento, il quale non sarà mai e poi mai né troppo né sufficiente.

Le problematiche di sicurezza devono essere tenute in considerazione sin dal principio, in sede di progetto: correggere nel seguito errori fatti precedentemente potrebbe rivelarsi costosissimo. Inoltre va detto che la sicurezza spesso si scontra con l'usabilità di un programma - ciò che nessuno ammette è che, in fin dei conti, per come viene usato un sistema informatico dagli utenti, la troppa sicurezza è nemica di se stessa.. In generale (ma molto in generale), più un programma è sicuro più è restrittivo e meno è usabile. Si deve sapere con esattezza a cosa un programma dovrà servire, sin dall'inizio. È bene tenerlo a mente.

Come è bene tenere a mente che scrivere un programma Web sicuro è solamente uno dei tanti passi per creare un'architettura Web sicura, in quanto i dati dell'applicazione in transito per la Rete, "payload" del protocollo HTTP, potrebbero essere intercettati o modificati anche se la nostra programmazione non fa una grinza: il protocollo TCP stesso, all'interno del quale "viaggia" l'HTTP, può presentare vulnerabilità piccole o grandi, così come un server od un client può essere bucato indipendentemente dalla nostra abilità di programmatori, se mal configurato o se in esso girano programmi bacati (come Internet Explorer), firewall mal impostati e via discorrendo.

Le pagine presenti trattano in maniera assolutamente prevalente di programmazione "sicura" relativamente al linguaggio PHP (prese come riferimento le versioni 4.4 e superiori) e dei linguaggi di scripting client-side correlati, come ad esempio JavaScript.

Quale prerequisito per la lettura, si dà per scontata una buona pratica nella programmazione con l'uso di tale linguaggio ed una conoscenza di base dei meccanismi che regolano l'interazione browser e Web server, in particolare il funzionamento dei protocolli coinvolti.


2) Sulla direttiva register_globals


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.

Consideriamo il seguente URL: test.php?documento=4&pagina=2. Nel caso la direttiva fosse attivata, per esso verranno create due variabili (globali) con i nomi e valori indicati dalle stringhe. 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 congegnato.

Poniamo infatti che la direttiva register_globals sia abilitata e l'applicazione Web PHP abbia al suo interno una funzione simile alla seguente:

<?
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();
}
?>

La funzione autenticazione() autentica l'utente, in base a qualsiasi metodo il programmatore ritenga opportuno, ed il risultato di tale procedura è memorizzato nella variabile $utente_autorizzato.

Tuttavia, non è assolutamente necessario che un cracker (che conosca comunque il codice del programma) superi la procedura di autenticazione per accedere al sistema: è sufficiente richiamare lo script come in figura, in quanto $utente_autorizzato è ugualmente valorizzato dalla variabile in GET.

Figura 1: esempio sul browser di accesso non protetto:

img_01.jpg


Poiché il cracker deve conoscere i dettagli del codice, va da sé che tali vulnerabilità riguardano essenzialmente gli applicativi open source.

Per nostra fortuna, infine, la direttiva in questione generalmente è oramai sempre disabilitata: stiamo solo attenti a non aprire vulnerabilità ormai in pensione modificandone il valore.

SOLUZIONI:

La direttiva register_globals deve essere impostata ad OFF, l'abbiamo già capito.

In ogni modo, che si intenda impostare register_globals ad OFF o no, 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 infatti l'inizializzazione della variabile $utente_autorizzato ad inizio script, l'exploit non funziona nemmeno con register_globals impostato ad ON:

// main
$utente_autorizzato = false;

Durante lo sviluppo del programma è inoltre consigliabile impostare, sempre nel file php.ini, la direttiva error_reporting ad E_ALL. Con questa impostazione, PHP evidenzia in fase di runtime ogni variabile non inizializzata:

Notice: Undefined variable: variabile in percorso\cartella\script.php on line xx

Non dimentichiamo, una volta terminata la fase di produzione, di impostare error_reporting in modo che ogni tipo di errore non venga più visualizzato, in quanto ogni output di questo tipo rivela la struttura interna del programma, intesa come nome e percorso degli script e via discorrendo. E il cracker non aspetta altro.

Come qui:

FPDF error: Unable to create output file:
../manuali/15022-MANUALI-MGCI--2006391/man/lista_manutenzioni.pdf
PHP Warning: stat failed for
../manuali/15022-MANUALI-MGCI--2006391/fscommand/manuali.list.xml
(errno=2 - No such file or directory) in E:\xxx\manual_maker\_mm_funct.php on line 208
Distinguere quindi tra direttive del php.ini in- e post-produzione.


3) Sugli include dinamici (via GET o POST)

INTRODUZIONE:

Si abbia uno script test.php, sul Web server di
Perfavore, Entra oppure Registrati per vedere i Link!
, poniamo all'indirizzo:
Perfavore, Entra oppure Registrati per vedere i Link!
.

<?
if (isset($_GET['include_script'])) include($_GET['include_script']);
// altro_codice;
?>

test.php include un file in modo dinamico, sulla base di quanto ricevuto via query string. Ricevendo in GET, ad esempio: ?include_script=dummy_script.php, quest'ultimo script viene incluso dinamicamente all'interno dello script principale test.php.

Sicuramente non rientra nelle intenzioni del programmatore l'eventualità che possa venir incluso un file remoto. Nelle intenzioni del cracker invece sì

Ecco come. Poniamo che il cracker prepari uno script, residente sul suo sito, del tipo
Perfavore, Entra oppure Registrati per vedere i Link!
come di seguito:

<?
echo "Inclusione dannosa riuscita.";
// altre istruzioni dannose;
?>

Se la direttiva allow_url_fopen del php.ini di dummy_site è abilitata, il cracker, inserendo da browser l'indirizzo:

Perfavore, Entra oppure Registrati per vedere i Link!

può facilmente eseguire il codice di evil_script su dummy_site.com. E prevedibilmente la fantasia dell'cracker sarà ben diversa dalla mia in quanto ad istruzioni eseguite. Ad esempio lo script potrebbe cercare e di seguito visualizzare file contenenti password del sistema ospite. O perché non i file di sessione? E così via.

Un'annotazione: la direttiva allow_url_fopen abilita i wrapper URL per fopen(), in modo da poter accedere agli oggetti URL come file. Essa è abilitata di default.

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:

if (isset($_GET['include_script']) && dirname($_GET['include_script'])==".")
{
include($_GET['include_script']);
}

È molto difficile, infatti, per il cracker riuscire a salvare un file nella directory virtuale di un server da remoto, se non in possesso dei relativi permessi. O in presenza di immensi buchi.

Oppure ancora, altro metodo, è sufficiente inserire tutte le pagine che intendiamo successivamente richiamare in un array ed in seguito verificarne la corrispondenza con la variabile in GET: se in GET è indicata una pagina non presente nell'array, essa non verrà inclusa. Questo secondo metodo scongiura una possibile vulnerabilità del primo: immaginiamo che include_script sia proprio test.php stesso: in teoria si scatenerebbe un processo di inclusione ricorsiva causando un DoS (Denial of Service) del Web server.

Rimane da sottolineare come gli include statici, del tipo: include("mio_file.php") non nascondono ovviamente alcun tipo di vulnerabilità.

4)HTTP Response Splitting

INTRODUZIONE:

Quanto detto al riguardo delle inclusioni dinamiche ha effetto anche per i rindirizzamenti dinamici via PHP. Si abbia l'istruzione seguente posta in un qualsiasi punto di uno script:

header("Location:".$_GET['GoTo']);

Non è necessario spiegare ulteriormente il possibile exploit: una query string ben studiata può rindirizzare il flusso della navigazione dove voluto. E sappiamo anche come difenderci.

Questa volta tuttavia non è finita qui: essendo eseguita lato server, l'istruzione header può indurre il browser a impostare un cookie (impostare un cookie infatti altro non vuol dire che inviare uno header opportuno) voluto dal cracker stesso, esattamente come se arrivasse, consciamente, dall'applicazione remota:

Perfavore, Entra oppure Registrati per vedere i Link!

Il comando PHP header non vedrà solamente il rindirizzamento, ma anche una seconda riga (%0D%0 è la codifica per gli URL di \r\n) in cui si invia appunto al client (la richiesta di impostare) il cookie.

Molto, ma molto, importante è che questo exploit potrebbe portare ad un attacco di tipo "session fixation" in quanto induce il browser a impostare un cookie contenente dati di sessione (vedere più avanti).

RIMEDIO:

Il rimedio è semplicissimo: evitare che il comando Set-Cookie possa esser inviato via query string, tramite la seguente riga di codice:

if (strpos(strtolower($_SERVER['REQUEST_URI']),"set-cookie:")!==false) exit;

Posta all'inizio di ogni script. Alternativamente - e più efficacemente - possiamo eliminare tutti i caratteri di CR+LF (ritorno a capo e nuova riga: \r\n). Da porre attenzione al fatto che Windows e Linux differiscono in tale codifica: la presente è quella usata dai sistemi operativi Windows.

NOTA:

Per visualizzare un cookie presente sulla nostra macchina utilizziamo, con Firefox, la seguente finestra: Strumenti / Opzioni / Privacy / Cookie.

I cookie standard usati da PHP per tener traccia dei dati di sessione (mantenendo cioè le impostazioni di default nel php.ini) scadono alla chiusura del browser: sono visualizzabili come sopra descritto ma non vengono salvati su filesystem locale, rimanendo in memoria per tutta la loro (in genere breve) vita.

5) Sui form e sulle validazioni lato client (JavaScript)

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, è già conservati nel database, nel box Nome tipo di un form Web:

Figura 2: un modulo di salvataggio dati
img_02.jpg


function verifica_nome(campo)
{
filesEsistenti=new Array();
filesEsistenti=['FAX','DOCUMENTO GENERICO','COMUNICAZIONI INTERNE','COMMESSA'];
// array eventualmente costruito dinamicamente da PHP.

if (filesEsistenti.in_array(campo.value.toUpperCase()))
{
alert ("Il nome utilizzato è già esistente. ");
campo.value = "";
campo.focus();
return true;
}
}

Ossia una funzione JavaScript richiamata tramite lo handler OnBlur nel relativo input box HTML:

<input type="text" name="nome_tipo" OnBlur="verifica_nome(this)">

Essendo, a sua volta, il form dichiarato come segue:

<form action="ins_tipo.php" method="post" enctype="multipart/form-data" name="form1" id="form1">

Vulnerabilità E Conclusioni

Un controllo lato client di questo tipo è però "bypassabile" in ben tre maniere semplicissime.


Eliminare I Controlli JavaScript


È sufficiente salvare il file HTML ed omettere (con qualsiasi editor testuale) i controlli JavaScript detti, avendo cura di modificare il parametro action del form in modo che punti all'URL del Web server in questione (qui:
Perfavore, Entra oppure Registrati per vedere i Link!


<form action="http://www.my_srv.com/ins_tipo.php" method="post" enctype="multipart/form-data" name="form1" id="form1">

<input type="text" name="nome_tipo" OnBlur="">


Utilizzare un socket


Lo stesso risultato può essere ottenuto inviando tale pagina, comprensiva di variabili POST, in HTTP via socket da un qualsivoglia programma (anche script PHP) oppure direttamente via Telnet (porta remota 80).

Disabilitare JavaScript

Come dite? Molto rumore per nulla? È sufficiente disabilitare il JavaScript dalle opzioni del browser? Già…

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 siamo solo all'inizio della guida...

Alcune volte i programmatori alle prime armi escludono possibili caratteri pericolosi esattamente in questo modo, solamente via JavaScript: abbiamo visto che è una pratica da evitare.

È da notare che un controllo di sessione non può nulla al fine di evitare simili attacchi, in quanto, una volta autenticati, possiamo spedire qualsiasi cosa desideriamo dal nostro client al server remoto. E potremo sempre dire di "non averlo fatto apposta"… in questo caso la parola spetterebbe sì ai legali, ma anche il programmatore sarebbe costretto a prendersi le sue (corpose) responsabilità.

Spero Di essere stato utile :emoji_relieved:
Ci ho messo un bel po a farla :P
Buon PHP Divertimento XD :emoji_relieved:

Thanks to HTML.it
 
Ultima modifica da un moderatore:
Pian piano, con forbici e colla vediamo cosa si fà :emoji_smiley: copia - incolla
LoL
 
Rinomino per l'errore.

Se si devono mettere i credits, è meglio che li mettete.

Se l'hai fatta tu, complimenti.
 
Ottima guida e mlt utile sopratutto a me :S

Se è davvero tua complimenti si :emoji_smiley:
 
Ho letto per sicurezza qualche guida poi ho riassunto per far capire meglio. Nelle altre guide è complicato per chi vuole imparare le prime basi :emoji_slight_smile:
Comunque qualsiasi info contattatemi su msn:
habbolane@hotmail.it
 
Ciao,

possiamo vitare di prendere in giro.
E' stato preso da
Perfavore, Entra oppure Registrati per vedere i Link!
[/URL]
Quindi sei pregato di mettere i Credits tutte le volte che copiuna guida e di evitare di prendere in giro in primo luogo lo Staff e poi gl ialtri utenti.
Pensa se a te copiano una guida e non mettono che stata scritta da te e si impossessano dei diritti non credo che tu ci rimanga tanto contento.
Grazie
 
Ultima modifica: