Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Proteggere PHP dai comandi di sistema

Come proteggere i nostri script quando hanno necessità di eseguire chiamate dirette ai comandi del sistema operativo: le funzioni escapeshellarg e escapeshellcmd
Come proteggere i nostri script quando hanno necessità di eseguire chiamate dirette ai comandi del sistema operativo: le funzioni escapeshellarg e escapeshellcmd
Link copiato negli appunti

Oltre che dai pericoli provenienti dall'esterno che sfruttano vulnerabilità interne ad un'applicazione, come per esempio SQL injection e Cross-site scripting, uno script può essere minacciato anche da pericoli provenienti dall'interno. Tra questi ci sono per esempio alcuni comandi di sistema, eseguiti sulla macchina server ospitante, che nel migliore dei casi potrebbero dare origine a malfunzionamenti fino a causare danni anche irreparabili ai dati gestiti.

In questa breve trattazione verrà approfondito l'argomento relativo alla protezione delle applicazioni PHP dai comandi di sistema, suggerendo alcuni accorgimenti pratici per aumentare il livello di sicurezza degli script.

I rischi derivanti dal sistema

I pericoli derivanti dall'esecuzione di comandi provenienti dal sistema devono essere valutati con particolare attenzione, soprattutto al giorno d'oggi in cui non capita di rado che gli script PHP debbano interagire con altre applicazioni, come per esempio istruzioni inviate tramite terminale; quando si crea il codice di un'applicazione, ad esempio un forum di discussione o un sistema per la gestione dei commenti, gli sviluppatori attenti non dimenticano certo di utilizzare i costrutti necessari per filtrare e validare gli input provenienti dai browser, quindi perché ignorare le minacce che possono derivare dai comandi di sistema?

Un semplice esempio aiuterà a capire l'importanza di questo concetto: si immagini un sistema in cui PHP è installato come un modulo del Web server. In questo caso PHP esegue dei comandi di che dovranno essere gestiti da Apache (o applicazioni simili), cosa potrebbe accadere se questa applicazione funzionasse utilizzando l'utente di root per l'invio delle istruzioni?

In linea teorica, e non di rado anche in via pratica, un'applicazione PHP che ha alle spalle le autorizzazioni illimitate di un utente di root potrebbe causare danni non solo ai dati che essa stessa gestisce (ad esempio: le informazioni contenute in un database), ma addirittura all'intero sistema in cui viene eseguita.

Da quanto esposto si ricava una prima semplice regola per la protezione dai comandi di sistema: il Web server non deve girare avendo il root come proprietario del suo processo (demone).

L'accorgimento appena descritto può essere utile per evitare di esporre le proprie applicazioni ad alcuni pericoli, ma non è del tutto risolutiva. Si immagini per esempio di dover creare un'applicazione per un istituto di credito che, al fine di concedere un prestito, permetta di controllare se un determinato cliente è in regola con le rate del mutuo acceso con la banca; ciò sarà possibile per esempio inviando una richiesta da una filiale verso il server della sede centrale utilizzando come parametro il codice relativo al cliente: /home/server/rate-mutuo.pl cod-xxxxx.

Ma cosa succederebbe se a questa istruzione fosse aggiunto un semplice comando come il seguente? /home/server/rate-mutuo.pl cod-xxxxx; less -c /etc/passwd.

L'esempio proposto descrive naturalmente una situazione estrema ed improbabile: un comando per la lettura di un file inviato da uno script che riesce ad accedere al database degli utenti presente in una piattaforma Unix o Linux, ma è utile per sottolineare quali sono i pericoli insiti nelle istruzioni inviate al sistema.

Di seguito verranno proposti alcuni accorgimenti per evitare, nel limite del possibile, di incorrere in problematiche come quella appena esposta.

I comandi per il sistema di PHP

Si immagini di voler eseguire uno script sul modello del seguente listato:

<?php
  // esecuzione di un comando esterno
  exec("ls -alF /var/www/website", $files);
  // visualizzazione del contenuto presente nel percorso specificato dal comando
  foreach($files as $file) {
    echo "{$file}<br />rn";
  }
?>

Di per sé l'istruzione contenuta nel codice appena proposto non è particolarmente pericolosa: la funzione exec() ha lo scopo di eseguire un comando esterno che nel caso specifico determina la visualizzazione di tutti i file e le cartelle presenti sul percorso /var/www/website, l'output della funzione è rappresentato da un array i cui elementi potranno essere stampati a video tramite un semplice ciclo foreach.

Oltre ad exec() vi sono altre funzioni che possono essere utilizzate per il lancio di comandi di sistema, le più importanti sono:

  • passthru(): ha il compito di eseguire un comando esterno e permette di restituire l'output prodotto direttamente tramite il browser per la navigazione Web;
  • shell_exec: esegue un comando via terminale (per esempio la shell dei sistemi operativi Unix e Linux) e restituisce l'output completo dell'esecuzione sotto forma di stringa;
  • system(): esegue un comando esterno e permette di visualizzare l'intero output, inoltre, tenta di ripulire l'output buffer del Web server dopo che viene restituita ciascuna riga del risultato.

Tutte le funzioni elencate eseguono comandi a livello di sistema, quindi tutte potrebbero essere causa di malfunzionamenti o danneggiamenti nel caso non vengano utilizzate con la dovuta accortezza.

Funzioni per il controllo sui comandi di sistema

Riprendendo l'esempio basato sul comando exec() proposto in precedenza, è possibile approfondire quanto esposto ponendosi una semplice domanda: cosa succederebbe se l'esecuzione di un comando dipendesse dall'invio di un input tramite metodo da parte di un client (per esempio attraverso un form)?

Si analizzi il seguente esempio di codice:

<?php
// controllo sull'invio del parametro
if(isset($_POST['codice_cliente']))
{
 $codice_cliente = $_POST['codice_cliente'];
//esecuzione del comando esterno
 exec("/home/server/rate-mutuo.pl {$codice_cliente}", $values);
//ciclo di visualizzazione
 foreach($values as $value) {
  echo "{$value}<br />rn";
  }
}
?>

In questo caso, il funzionamento dello script richiede il passaggio di un parametro inviato tramite metodo POST ($codice_cliente) che è anche argomento della funzione exec(); si immagini cosa potrebbe accadere se il parametro contenesse anche una qualsiasi istruzione arbitraria indirizzata al sistema, come, per esempio, /home/server/rate-mutuo.pl cod-xxxxx; less -c /etc/passwd

Fortunatamente PHP è fornito anche di alcune utili funzioni native per la sicurezza dei comandi di sistema, che permettono di limitare gli effetti nefasti di questo tipo di problematiche, esse sono escapeshellarg() e escapeshellcmd().

Le funzioni per l'escaping dei comandi di sistema

escapeshellarg

escapeshellarg() è stata concepita per effettuare l'escape (o "quoting" o più semplicemente "delimitazione tra apici") di una stringa da utilizzare come argomento per un istruzione da inviare tramite shell; in pratica questa funzione non fa altro che aggiungere dei singoli apici all'inizio e alla fine di una stringa e consente di effettuare l'escape di eventuali apici singoli preesistenti, in questo modo l'utilizzatore avrà la possibilità di passare una stringa resa sicura direttamente ad un'istruzione da inviare tramite terminale. Utilizzare escapeshellarg() è molto semplice:

<?php
// $_POST['cartella'] = '/var/www/website';
$cartella = $_POST['cartella'];
system('ls -t '.escapeshellarg($cartella));
?>

Nell'esempio proposto, il contenuto della variabile $cartella verrà concatenato al comando ls -t all'interno dell'istruzione dopo l'escape operato dalla funzione escapeshellarg(), in modo che esso risulti sicuro nel momento in cui viene passato a system().

escapeshellcmd

escapeshellcmd() ha invece un compito diverso, essa infatti è stata concepita per effettuare l'escape dei metacaratteri (caratteri che in una stringa rappresentano insiemi di altri caratteri o anche delle sequenze di caratteri) da un parametro utilizzabile come argomento per un'istruzione da terminale. In pratica si tratta di una funzione che effettua l'escape di qualsiasi carattere presente in una stringa che possa essere utilizzato per alterare l'esecuzione di un'istruzione introducendo comandi arbitrari.

Anche l'utilizzo di questa funzione è estremamente semplice:

<?php
// $_POST['sorgente'] = '/home/immagini_2009';
// $_POST['destinazione'] = '/home/archivo/immagini';
$sorgente = $_POST['sorgente'];
$destinazione = $_POST['destinazione'];
$istruzione = exec(escapeshellcmd('cp -r '. $sorgente . ' ' . $destinazione'));
?>

Nell'esempio proposto, tutti i parametri inviati tramite input dell'utente subiscono il quoting dovuto alla funzione escapeshellcmd() prima di essere passati come argomenti a exec() ed entrare quindi a far parte dell'istruzione da terminale.

Conclusioni

In questa breve trattazione sono state fornite alcune indicazioni sui rischi derivanti dall'esecuzione di comandi di sistema tramite PHP, inoltre, sono state proposte le funzioni essenziali per limitare i pericoli derivanti da questo tipo di istruzioni, ponendo particolare attenzione ai costrutti che consentono di effettuare l'escape degli input inviati dagli utenti.

Ti consigliamo anche