Sicurezza in PHP

Da Hacknowledge.

Rendere un sito sicuro e' tendenzialmente semplice, i bug escono solo attraverso la disattenzione quindi e' sufficiente ridurre le possibilita' di dimenticanze e stare molto attenti in sorgenti che potrebbero causare vulnerabilita'.

Indice

[modifica] RFI

Per evitare gli RFI e' sufficiente evitare di fare include/require utilizzando variabili su cui non si ha controllo, quindi EVITATE come la peste obbrobri tipo:

// Se non fosse chiaro questo e' da EVITARE
$page = $_GET['page'];
include($page);

O ve lo meriterete di trovarvi il server piallato da una shell.

[modifica] LFI

Evitare gli LFI e' semplicissimo, basta tenere sotto controllo una variabile e limitare l'agire su una cartella sola:

define('ROOT_PATH', dirname(__FILE__));
 
$page = preg_replace('|\.+/+|', '', $_GET['page']);
include(ROOT_PATH."/include/{$page}");

[modifica] XSS

Per evitare gli XSS il metodo e' molto semplice, basta usare SEMPRE htmlentities sull'output e stare attenti a come si scrivono le regex.

Esempio di vulnerabilita' con le regex (pseudocodice):

$input = "[img width=124 height=645]javascript: alert('XSS')[/img]";
 
regex =~ s|\[img width=["]?(\d+)["]? height=["]?(\d+)["]\](.+?)\[/img]|<img src="$3" width="$1" height="$2"/>|

Come potrete notare questa regex prendera' i contenuti e finira' con il mandare in output <img src="javascript: alert('XSS')" etc/> causando cosi' un XSS.

[modifica] CSRF

Il metodo per evitare i CSRF e' creare un magic token che viene salvato in sessione ed inviare SEMPRE con ogni form lo stesso token per poi fare un controllo che quello arrivato in ingresso e quello in sessione siano uguali.

In succo bisogna tenere in $_SESSION['magic'] una stringa qualsiasi, magari creata via md5 con una funzione random e stamparla nel form in modo che solo la corrente sessione possa conoscerla.

In questo modo un malintenzionato non potra' effettuare un CSRF visto che non potra' conoscere il magic token.

Consiglio di cambiare il token ogni volta che un form viene ricevuto, in questo modo le probabilita' che qualcuno possa azzeccarlo calano drasticamente.

[modifica] SQL Injection

Evitare un SQL injection e' davvero semplicissimo, l'importante e' stare attenti quando si inviano dati al database.

Per filtrare i dati in ingresso al database dovete semplicemente filtrate con (int) gli interi e con mysql_real_escape_string le stringhe, esempio:

In ingresso ho due campi GET: name ed age.

$nome = mysql_real_escape_string($_GET['name']);
$age  = (int) $_GET['age'];
 
mysql_query("INSERT INTO table VALUES('{$name}', {$age})");

Per usare mysql_real_escape_string e' necesario che ci sia una connessione a mysql aperta (ma ovviamente non avrebbe senso usarla altrimenti :P).

Per il database e' comunque consigliato creare una classe che parsi in automatico i parametri passati in ingresso, si potrebbe fare un metodo sendQuery e passargli i parametri attraverso un array diviso in 3 parti (string, int, float) e fare qualcosa di questo tipo:

foreach ($array as $type) {
    foreach ($type as $key => $value) {
        if ($type == 'string') {
            $array[$type][$key] = mysql_real_escape_string($value);
        }
        else if ($type == 'int') {
            $array[$type][$key] = (int) $value;
        }
        else if ($type == 'float') {
            $array[$type][$key] = (float) $value;
        }
    }
}

In questo modo si potra' mettere in un array ogni valore di che tipo dovrebbe essere e ci pensera' la funzione a fare il resto :)

Filtrati i valori si potra' tranquillamente inviare la query.

[modifica] Log poisoning

In caso si vogliano salvare dei log degli accessi e non si voglia renderli visibili ad altri utenti salvandoli quindi in un file php per evitare che qualcuno possa fare danni inserendo codice malevolo all'interno dei log basta mettere un die(); all'inizio del file di log.

Alternative non dipendenti dal php sarebbero mettere il file sotto la / del server o in una cartella vietata dall'.htaccess.

Strumenti personali