La sicurezza degli script PHP si concentra essenzialmente su due aspetti: prevenire il cross-site scripting (CSS o XSS) e prevenire lo spionaggio dei dati o l'inserimento di codice. Per questo motivo è particolarmente importante controllare tutte le voci che provengono dall'esterno, e cioè dati trasferiti nell'URL, dati dei moduli, cookie e file caricati.

Nota bene: L'elenco delle precauzioni di sicurezza qui riportato non ha la pretesa di essere esaustivo, ma funge solo da punto di partenza per l'individuazione dei rischi principali.

Un piano di sicurezza protegge sempre il software nella sua interezza e copre in modo coerente tutti gli ambiti dell'elaborazione dei dati. La protezione degli script è solo uno dei componenti di questo piano di sicurezza.

Inserisci codice tramite include()

Una falla di sicurezza comune è dovuta all'uso della funzione include() con parametri variabili. Un pirata informatico potrebbe infatti approfittare di questa funzione e inserire codice estraneo immettendo un indirizzo URL come parametro. Questo codice, determinato liberamente dal pirata informatico, viene poi eseguito come se fosse parte dello script; il cracker può così sfruttare tutte le possibilità dello script. Evita perciò di usare la funzione include() con valori variabili e utilizza piuttosto costanti. Se l'uso di variabili non può essere evitato, applica al loro contenuto i filtri necessari, come nel seguente esempio:

if (strpos($variable, '://') !== FALSE || strpos($variable, '../') !== FALSE)
die('Illegal string'); 

Questo codice controlla se le stringhe ://, come in http:// o ftp://, oppure .., come in ../.../secret/passwords, sono contenute nella stringa $variabile e termina l'esecuzione, se necessario.

SQL Injection

Quando uno script utilizza query al database, è relativamente facile per un pirata informatico iniettare codice SQL se lo script non è programmato correttamente. Ciò gli consente di leggere, modificare o addirittura cancellare dati ai quali altrimenti non avrebbe accesso.

Supponiamo di utilizzare il seguente codice in uno script:

[...]
$sql = "SELECT * FROM adressen WHERE name='".$_GET['name']."'";
$result = mysql_query($sql);
[...]        

Questa query o una simile può comparire se si desidera filtrare l'indirizzo di un nome particolare da una tabella contenente una serie di indirizzi.
L'hacker può ora chiamare l'URL http://dominio.tld/skript.php?name=';DELETE FROM adressen WHERE 1=1 OR name='.
Ne risulta una query SQL SELECT * FROM adressen WHERE name=''; DELETE FROM adressen WHERE 1=1 OR name='';. In primo luogo, il server del database seleziona tutti i record per i quali il campo Nome contiene una stringa vuota, in seguito tutti i record vengono eliminati dalla tabella. Naturalmente, questa falla può essere utilizzata anche per altri scopi, la cancellazione del contenuto della tabella dovrebbe fungere solo da esempio in questo caso.

Per evitare questa falla di sicurezza, le variabili nelle query SQL dovrebbero sempre essere trasformate utilizzando la funzione mysql_real_escape_string(). I caratteri speciali, come le virgolette singole, vengono mascherati in modo da essere interpretati come parte dell'intera stringa e non come caratteri per la fine della stringa stessa. Se i valori vengono superati al di fuori delle virgolette (ad esempio valori numerici), utilizzare la funzione intval() se possibile. Questo assicura che venga effettivamente utilizzato un solo valore numerico, ecco un esempio:

Trasferimento di parametri negli URL

Il passaggio di parametri negli URL (ad esempio http://domain.tld/script.php?id=1) è un modo comune per passare argomenti agli script. Tuttavia, si dovrebbe sempre essere consapevoli che questi parametri possono essere impostati a piacimento dall'utente. Ciò significa che il suo contenuto deve essere considerato inaffidabile. Lo stesso vale per i dati trasmessi via email HTTP e i cookie.

Questo è importante quando si esegue il reindirizzamento da uno script a un altro e si passano parametri nell'URL o come cookie. Il nuovo script non può considerare questi parametri affidabili, ma deve controllarli tutti di nuovo. Spesso è più facile usare le funzioni di sessione di PHP. I dati che sono stati controllati e memorizzati nella sessione possono ora essere classificati e utilizzati come sicuri. L'utente non ha la possibilità di modificare direttamente il contenuto della sessione.
L'identificatore di sessione viene passato come parametro con l'URL. Poiché si tratta di una stringa generata in modo casuale, la probabilità che un attaccante possa indovinare l'identificatore di una sessione estranea è estremamente bassa.

Variabili globali

Nelle versioni precedenti di PHP, i parametri passati dai form o nell'URL erano inseriti in variabili globali. Per ragioni di compatibilità, tuttavia, le versioni attuali riproducono ancora questo comportamento nella maggior parte dei sistemi.
Ad esempio, se viene richiamato l'URL http://dominio.tld/skript.php?variable=contenuto, viene impostata nello script una variabile con il nome $variabile e il contenuto.

Questo può diventare un problema se si utilizzano le variabili globali internamente senza inizializzarle correttamente in anticipo.

Esempio:

<?php
if ($_GET['password'] == 'geheim') {
$admin = true;
}

[...]

if ($admin) {
// Aktionen, die einem Administrator, der das Passwort kennt, vorbehalten sind
[...]
}
?>

Un aggressore può semplicemente chiamare l'URL http://dominio.tld/skript.php?admin=1 e ha immediatamente i diritti di amministratore, perché la variabile $admin restituisce true.

Con una corretta inizializzazione, questo può essere evitato

<?php
$admin = false;

if ($_GET['password'] == 'geheim') {
$admin = true;
}

[...]

if ($admin) {
// Aktionen, die einem Administrator, der das Passwort kennt, vorbehalten sind
[...]
}
?>

Ora il valore precedentemente impostato per $admin viene prima sovrascritto e impostato a true solo se la password è stata effettivamente passata.

In altri scenari, l'omissione dell'inizializzazione può essere utilizzata anche per le iniezioni SQL, ad esempio. Per questo motivo ci si dovrebbe abituare ad inizializzare tutte le variabili, anche se la sintassi di PHP non lo richiede.

Cross-Site-Scripting

Lo scripting tra siti è il caso in cui un aggressore inserisca codice JavaScript in un sito straniero per ottenere informazioni alle quali normalmente non ha accesso. Può essere utilizzato per accedere ad altri ID di sessione o per spiare i nomi utente.
A tale scopo, l'aggressore crea un URL in cui imposta i parametri che vengono immediatamente visualizzati nel testo della pagina. Se questo testo ora contiene codice script, viene eseguito nel contesto di sicurezza della pagina, ad esempio può leggere i cookie che sono stati impostati da questa pagina. Il pericolo di questo tipo di attacco è che sia quasi invisibile per l'utente quando si verifica in un fotogramma nascosto.

La soluzione è quella di usare la funzione htmlentities() nello script per tutte le variabili da produrre (specialmente quelle che contengono input dell'utente).
Questo sostituisce i caratteri con un significato speciale in HTML, come < >,">',", con le entità corrispondenti. Questa semplice misura consente di eliminare la maggior parte delle possibilità di attacco per lo scripting tra siti.