SQL INJECTION ATTACK PREVENTION IN PHP / CODE EXAMPLES

Dopo diversi anni di test di penetrazione e di lavoro con i team di sviluppo per proteggere i loro sistemi, ho notato che non esisteva un post sul blog completo che fornisse una spiegazione dettagliata di come prevenire gli attacchi SQL injection in tutti i linguaggi e framework di sviluppo di applicazioni web più diffusi. Pertanto, ho deciso di scrivere una serie di post multipli per renderlo la guida più completa per prevenire l’iniezione SQL.

Questa guida è una serie aperta di post e questo è il primo post. Se vuoi che aggiunga qualsiasi tecnologia, per favore commenta qui sotto e sarò molto felice di spiegare la prevenzione di SQL injection per quella tecnologia. Questa guida analizza le seguenti tecnologie:

  • PHP
    • Laravel
    • Symfony
    • CodeIgniter
    • CakePHP
    • FuelPHP
    • Zend
  • JEE
    • JDBC
    • JPA
  • ASP.NET
    • ADO.NET
    • ADO.RETE Doper
    • NHibernate

Questo primo post si concentrerà sul linguaggio PHP e su tutti i suoi framework. Altri articoli seguiranno per affrontare le altre tecnologie elencate.

Per coloro che non sanno cosa sia l’attacco SQL injection, fammi fare una piccola introduzione per spiegarlo loro. Gli attacchi SQL injection si verificano quando un utente errato tenta di iniettare una richiesta SQL dannosa in una richiesta legittima. L’impatto dell’attacco SQL injection differisce da una situazione all’altra a seconda di più elementi relativi all’ambiente dell’app e può passare da “semplice” come perdita di informazioni a un controllo completo del server. Non voglio andare più in profondità nel modo in cui un utente malintenzionato potrebbe sfruttare questa vulnerabilità o come possiamo scoprirlo nei test blackbox in quanto questo non è l’obiettivo di questo post. Quello che vedremo è come scoprirlo nel codice sorgente e come risolverlo.

Come prevenire l’attacco SQL injection in un codice sorgente PHP puro ?

Iniziamo il nostro viaggio con una delle più antiche e popolari tecnologie di sviluppo PHP senza alcun framework. Ora la prima cosa da fare è sapere come appare una riga di codice sorgente vulnerabile per essere in grado di identificare la vulnerabilità.

Ecco un esempio di una richiesta di autenticazione:

$request = "SELECT * FROM users WHERE username=". $_POST ." AND password = ". $_POST;
$result = $mysqli->query($request);

Ora, se si dà un’occhiata da vicino alla richiesta, si noterà che i parametri utente _ _POST e _ _POST vengono iniettati direttamente nella richiesta SQL senza alcun filtro. In questo modo, questa riga di codice è vulnerabile all’iniezione SQL.

Per risolvere questa vulnerabilità è necessario filtrare i dati prima di utilizzarli nella richiesta sql. Per fare ciò la soluzione migliore è usare le dichiarazioni preparate. Ecco un esempio di come è possibile utilizzare le istruzioni preparate per risolvere questa vulnerabilità:

$conn = new mysqli($servername, $username, $password, $dbname);
$stmt = $conn->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->bind_param($username, $password);
$stmt->execute();

Buona pratica

Hai la possibilità di non usare la funzione bind_param() ecco un esempio di come farlo :

$conn = new mysqli($servername, $username, $password, $dbname);
$stmt = $conn->prepare("SELECT * FROM users WHERE username=:username AND password=:password");
$stmt-> execute(array('username'=>$_POST,'password'=>$_POST));

Dopo anni di analisi dei codici sorgente have ho scoperto un errore interessante che molti sviluppatori fanno mentre risolvono questa vulnerabilità. Dai un’occhiata al seguente esempio:

$stmt = $conn->prepare("SELECT * FROM users WHERE username=".$_POST." AND password=".$_POST);

Se guardi questo esempio, vedrai che stiamo usando le dichiarazioni preparate. Tuttavia, i parametri vengono iniettati direttamente nella richiesta SQL. Questo è un errore molto comune che gli sviluppatori fanno e rendono il codice vulnerabile a SQL injection anche se usiamo le istruzioni preparate.

L’idea alla base delle istruzioni preparate è quella di filtrare i parametri prima di iniettarli nella richiesta SQL-tienilo a mente.

Nota molto importante:

PHP offre alcune altre funzioni per filtrare le richieste SQL e impedire l’iniezione SQL, ma alcune di esse non sono efficienti. La funzione mysql_real_escape_string (), ad esempio, è una delle funzioni PHP più note per prevenire l’iniezione SQL. Sfortunatamente, questa funzione è davvero efficiente. Utilizzando questa funzione, la libreria MySQL aggiungerà una barra rovesciata ai seguenti caratteri: NULL, \ x00, \ n, \ r,\,’, “e \ x1a. Tuttavia, per una situazione come questa :

$id = mysql_real_escape_string("1 OR 1=1");
$request = "SELECT * FROM users WHERE id = $id";

In colore rosso è ciò che un cattivo utente ti invierà

mysql_real_escape_string () non ti proteggerà da tale attacco.

Questo è il motivo per cui raccomando sempre di usare le istruzioni preparate invece di questa funzione.

Come prevenire l’attacco SQL injection in Laravel framework ?

Ora che abbiamo visto l’attacco SQL injection contro un codice PHP puro, ora è il momento di vedere come possiamo risolvere la vulnerabilità in un’applicazione web basata su framework. Prima di iniziare a parlare di questo, permettetemi prima di darvi una piccola descrizione del framework Laravel.

Laravel è un framework web open source scritto in PHP rispettando il principio model-view-controller e sviluppato interamente nella programmazione orientata agli oggetti.

Esempio 1

Ecco un esempio di una richiesta SQL vulnerabile in un laravel :

$user = DB::select('select * from users where username='. $request->post('username').' AND password='. $request->post('password'));

Il framework Laravel offre alcune fantastiche funzioni per aiutare gli sviluppatori a proteggere la richiesta SQL da iniezioni dannose. Sfortunatamente, la maggior parte delle vulnerabilità di SQL injection che scopro in tali app sono legate all’uso improprio delle funzioni Laravel.

Analizziamo l’esempio precedente, secondo la documentazione di Laravel la funzione DB:: select potrebbe ricevere due parametri. Il primo è la richiesta SQL e il secondo sono i parametri. Quindi per filtrare i parametri per SQL injection dovrai inserire i parametri nella richiesta usando il secondo parametro proprio come questo esempio:

user user = DB:: select(‘select * from users where username=? E password=?’, );

Esempio 2

Laravel ha diversi modi per comunicare con il database in questo esempio vedrai che laravel costringe lo sviluppatore a utilizzare alcune funzioni che filtrano automaticamente i dati dell’utente, come il seguente esempio:

Users::where('username', $request->get('username'))->orderBy($request->get('orderby'))->get();

Questa funzione dovrebbe essere protetta contro SQL injection e lo sono, l’unico problema è a livello di funzione orderBy (). Secondo la documentazione di Laravel, questa funzione non filtra i dati dell’utente, quindi è ancora possibile un attacco SQL injection attraverso questa funzione.

La cosa migliore da fare è non dare all’utente la possibilità di controllare il nome della tabella, ma se questo è qualcosa di inevitabile, allora sarà necessario utilizzare una lista bianca per convalidare i dati dell’utente prima di inserirlo in quella funzione.

Come prevenire l’attacco SQL injection in Symfony ?

Vediamo un altro noto framework PHP che offre una serie di componenti PHP riutilizzabili per accelerare lo sviluppo di app PHP. Symfony è utilizzato anche da alcuni dei CMS web più noti come Drupal e Magento.

Symfony è uno dei framework più sicuri con cui è possibile lavorare, offre un ampio numero di funzioni per scrivere un codice sicuro. Tuttavia, se queste funzioni non sono ben utilizzate, si ottiene un codice vulnerabile. Quindi ecco un esempio di un codice vulnerabile:

$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery('SELECT p
FROM App\Entity\Product p
WHERE p.price > '. $request->query->get('price')
);

Ora analizziamo questo codice vulnerabile. Secondo la documentazione di Symfony, createQuery () è una funzione che utilizza per impostazione predefinita le istruzioni preparate. Quindi, l’oggetto risultante da tale funzione consente di accedere alla funzione setParameter (). Questo filtra tutti i dati dell’utente per evitare un’iniezione SQL. Ecco un esempio di come usarlo :

$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery('SELECT p
FROM App\Entity\Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', $price);

Come prevenire l’attacco SQL injection in Codeigniter ?

CodeIgniter uno dei framework PHP più potenti, leggeri e popolari con un ingombro molto ridotto. E ‘ stato costruito per gli sviluppatori che hanno bisogno di un toolkit semplice ed elegante per creare applicazioni web full-optional. Come Symfony e Laravel, Codeigniter viene fornito con alcuni sistemi di sicurezza per aiutare gli sviluppatori a creare applicazioni più sicure.

Tuttavia, anche con Codeigniter alcuni sviluppatori commettono lo stesso errore e iniettano i dati dell’utente senza alcun filtro. Ecco un esempio di tali errori che portano a un attacco SQL injection:

$query = 'SELECT * FROM users WHERE username = '. $this-> input->post('username'). ' AND password= '. $this-> input->post('password');
$this->db->query($query);

Ora per risolvere questo problema, è necessario dare un’occhiata alla documentazione di Codeigniter. Secondo esso, la funzione query () prende due parametri. Il primo è la query sql e il secondo sono i parametri che si desidera associare.

Esempio 1

Per impostazione predefinita, questa funzione filtra tutti i parametri associati per evitare iniezioni SQL. Ecco un esempio del modo corretto di utilizzare questa funzione:

$query = 'SELECT * FROM users WHERE username = ? AND password = ? ';
$this->db->query($query, array($this->input->post('username'), $this-> input-> post('password')));

Esempio 2:

Codeigniter fornire un altro modo per eseguire la richiesta SQL impedirà iniezioni SQL. Ecco un esempio di utilizzo della classe Record attiva per prevenire le iniezioni SQL:

$this->db->get_where('users',array('username'=>$this->input->post('username') ,'password' => $this->input->post('password')));

La funzione get_where () non esiste più nella versione 4 di Codeigniter.

Nota 1

Codeigniter offrono anche una funzione che assomiglia, mysql_real_escape_string () funzione chiamata escape (). Ma, come ho detto per la prima volta mysql_real_escape_string () potrebbe essere bypassato in alcuni casi e devi evitare di usarlo. Il fatto che la funzione escape() faccia esattamente lo stesso, allora sarebbe possibile bypassarlo anche. Questo è il motivo per cui non incoraggio gli sviluppatori a utilizzare la funzione escape ().

Nota 2

Come prevenire l’attacco SQL injection in CakePHP ?

CakePHP è un framework di sviluppo rapido per PHP che utilizza modelli di progettazione comunemente noti come la mappatura dei dati associativi, Front Controller e MVC. CakePHP offrono un gruppo di componenti integrati per facilitare lo sviluppo di applicazioni web e renderli più sicuri.

Tuttavia, le app CakePHP sono anche vulnerabili alle iniezioni SQL se non sono ben utilizzate. Ecco un esempio di un codice vulnerabile all’attacco SQL injection in questo framework:

$results = $connection-> execute('SELECT * FROM users WHERE username = '. $this->request->getParam('username').' AND password='. $this->request->getParam('password'))->fetchAll('assoc');

La funzione execute () per impostazione predefinita utilizza le istruzioni preparate. Tuttavia, l’esempio precedente è ancora vulnerabile all’attacco SQL injection, poiché i dati utente vengono inseriti direttamente in una richiesta sql legittima. Ecco un esempio del modo giusto per utilizzare questa funzione:

$results = $connection->execute('SELECT * FROM users WHERE username = :username AND password=:password', )->fetchAll('assoc');

Il framework CakePHP offre anche un sistema chiamato Query Builder, che forza il filtraggio dei dati degli utenti per prevenire attacchi SQL injection. Secondo la documentazione di CakePHP, Sotto le copertine, il Generatore di query utilizza le istruzioni preparate.

Ecco un esempio di come è possibile utilizzare tale sistema nel modo giusto:

use Cake\ORM\Locator\LocatorAwareTrait;
$users = $this->getTableLocator()->get('users');
// Start a new query.
$query = $users->find();
$query->where();

Come prevenire l’attacco SQL injection in FuelPHP ?

FuelPHP è uno dei più recenti framework PHP che è nato sulla base delle migliori idee di ogni framework sul mercato. È stato sviluppato con PHP 5 ed è completamente orientato agli oggetti. In FuelPHP, la sicurezza era il fronte e il centro della preoccupazione, che ha spinto i suoi contributori a implementare molti meccanismi di sicurezza per filtrare i dati degli utenti. SQL injection attacca uno dei motivi per implementare tali meccanismi in FuelPHP.

Tuttavia, anche con un framework così potente, un semplice uso improprio di questi meccanismi mette l’intero codice in pericolo per un attacco SQL injection. Ecco un esempio di tale errore di codice:

$query = "SELECT * FROM article WHERE id = ". Input::get('id');
$result = DB::query($query)->execute();

Per risolvere questo problema, ci sono anche due tecniche come gli altri framework. Il primo è quello di utilizzare correttamente la funzione query (), legando i parametri come il seguente esempio :

$query = "SELECT * FROM article WHERE id = :id"; // our query
$result = DB::query($query)->bind('id', Input::get('id'))->execute();

La seconda soluzione utilizza il meccanismo ORM implementato nel framework FuelPHP per comunicare con il database. Ecco un esempio di come usarlo:

$user = DB::select()->from('article')->where('id', Input::get('id'))->execute();

Come prevenire l’attacco SQL injection in zend framework ?

Zend framework (cambiato in Laminas Project) è uno dei framework più conosciuti nel mondo di PHP. È stato sviluppato pensando alla messa a punto delle prestazioni, il che spiega perché ogni nuova versione è molto più veloce di quella vecchia. Zend è stato anche sviluppato con le migliori pratiche di sicurezza, che ha spinto i suoi sviluppatori di implementare meccanismi di sicurezza aggiuntivi per affrontare le minacce informatiche noti.

Alcuni di questi meccanismi sono stati implementati per gestire gli attacchi SQL injection. Ma come sempre un uso improprio di tali meccanismi porta a un codice vulnerabile. In questa parte dell’articolo mostrerò un esempio di tale errore:

$adapter->query('SELECT * FROM `article` WHERE `id` = '. $this->getRequest()->getPost('id'));

Ecco come risolvere questa vulnerabilità:

$adapter->query('SELECT * FROM `article` WHERE `id` = ?', );

Leave a Reply