VERHINDERUNG VON SQL-INJECTION-ANGRIFFEN IN PHP / CODEBEISPIELE
Nach mehreren Jahren Penetrationstests und der Zusammenarbeit mit Entwicklungsteams zur Sicherung ihrer Systeme ist mir aufgefallen, dass es keinen vollständigen Blogbeitrag gab, in dem ausführlich erläutert wird, wie SQL-Injection-Angriffe in allen gängigen Sprachen und Frameworks für die Entwicklung von Webanwendungen verhindert werden können. Daher habe ich beschlossen, eine Reihe von mehreren Beiträgen zu schreiben, um die vollständigste Anleitung zur Verhinderung von SQL-Injection zu erstellen.
Dieser Leitfaden ist eine offene Reihe von Beiträgen und dies ist der erste Beitrag. Wenn Sie möchten, dass ich irgendeine Technologie hinzufüge, kommentieren Sie bitte einfach unten und ich werde sehr glücklich sein, SQL Injection Prevention für diese Technologie zu erklären. In diesem Handbuch werden die folgenden Technologien analysiert:
- PHP
- Laravel
- Symfony
- CodeIgniter
- CakePHP
- FuelPHP
- Zend
- JEE
- JDBC
- JPA
- ASP.NET
- ADO.NET
- UMSCHWEIFE.NET Dopper
- NHibernate
Dieser erste Beitrag konzentriert sich auf die PHP-Sprache und alle ihre Frameworks. Weitere Artikel werden folgen, um sich mit den anderen aufgeführten Technologien zu befassen.
Für diejenigen, die nicht wissen, was SQL Injection Attack ist, lassen Sie mich eine kleine Einführung geben, um ihnen dies zu erklären. SQL-Injection-Angriffe treten auf, wenn ein böswilliger Benutzer versucht, eine böswillige SQL-Anforderung in eine legitime Anforderung einzufügen. Die Auswirkungen eines SQL-Injection-Angriffs unterscheiden sich von Situation zu Situation, abhängig von mehreren Elementen, die sich auf die App-Umgebung beziehen, und können von “einfach” wie Informationslecks bis hin zu einer vollständigen Serversteuerung reichen. Ich werde nicht näher darauf eingehen, wie ein Angreifer diese Sicherheitsanfälligkeit ausnutzen kann oder wie wir sie in Blackbox-Tests entdecken können, da dies nicht das Ziel dieses Beitrags ist. Was wir sehen werden, ist, wie man es im Quellcode entdeckt und wie man es repariert.
Wie kann ein SQL-Injection-Angriff in einem reinen PHP-Quellcode verhindert werden?
Beginnen wir unsere Reise mit einer der ältesten und beliebtesten Entwicklungstechnologien PHP ohne Frameworks. Nun müssen Sie zunächst wissen, wie eine anfällige Quellcodezeile aussieht, um die Sicherheitsanfälligkeit identifizieren zu können.
Hier ist ein Beispiel für eine Authentifizierungsanforderung:
$request = "SELECT * FROM users WHERE username=". $_POST ." AND password = ". $_POST;
$result = $mysqli->query($request);
Wenn Sie sich nun die Anforderung genau ansehen, werden Sie feststellen, dass die Benutzerparameter $ _POST und $ _POST ohne Filterung direkt in die SQL-Anforderung eingefügt werden. Dadurch wird diese Codezeile anfällig für SQL-Injection.
Um diese Sicherheitsanfälligkeit zu beheben, müssen Sie die Daten filtern, bevor Sie sie in der SQL-Anforderung verwenden. Um dies zu tun, ist die beste Lösung, die vorbereiteten Anweisungen zu verwenden. Hier ist ein Beispiel, wie Sie die vorbereiteten Anweisungen verwenden können, um diese Sicherheitsanfälligkeit zu beheben:
$conn = new mysqli($servername, $username, $password, $dbname);
$stmt = $conn->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->bind_param($username, $password);
$stmt->execute();
Gute Praxis
Sie haben die Möglichkeit, die Funktion bind_param() nicht zu verwenden Hier ist ein Beispiel dafür :
$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));
Nach Jahren der Analyse von Quellcodes … habe ich einen interessanten Fehler entdeckt, den viele Entwickler bei der Behebung dieser Sicherheitsanfälligkeit machen. Schauen Sie sich das folgende Beispiel an:
$stmt = $conn->prepare("SELECT * FROM users WHERE username=".$_POST." AND password=".$_POST);
Wenn Sie sich dieses Beispiel ansehen, werden Sie sehen, dass wir die vorbereiteten Anweisungen verwenden. Die Parameter werden jedoch direkt in die SQL-Anforderung eingefügt. Dies ist ein sehr häufiger Fehler, den Entwickler machen, und macht den Code anfällig für SQL-Injection, selbst wenn wir die vorbereiteten Anweisungen verwenden.
Die Idee hinter den vorbereiteten Anweisungen besteht darin, die Parameter zu filtern, bevor sie in die SQL-Anforderung eingefügt werden.
Sehr wichtiger Hinweis:
PHP bietet einige andere Funktionen, um SQL-Anfragen zu filtern und SQL-Injection zu verhindern, aber einige von ihnen sind nicht effizient. Die Funktion mysql_real_escape_string() zum Beispiel ist eine der bekanntesten PHP-Funktionen, um SQL-Injection zu verhindern. Leider ist diese Funktion sehr effizient. Mit dieser Funktion fügt die MySQL-Bibliothek den folgenden Zeichen einen Backslash hinzu: NULL, \ x00, \ n, \ r, \, ‘, “und \ x1a. Für eine Situation wie diese :
$id = mysql_real_escape_string("1 OR 1=1");
$request = "SELECT * FROM users WHERE id = $id";
In roter Farbe ist das, was ein schlechter Benutzer Ihnen sendet
Der mysql_real_escape_string() schützt Sie nicht vor einem solchen Angriff.
Aus diesem Grund empfehle ich immer, die vorbereiteten Anweisungen anstelle dieser Funktion zu verwenden.
Wie kann ein SQL-Injection-Angriff im Laravel-Framework verhindert werden?
Nun, da wir den SQL-Injection-Angriff gegen einen reinen PHP-Code gesehen haben, ist es an der Zeit zu sehen, wie wir die Sicherheitsanfälligkeit in einer Framework-basierten Webanwendung beheben können. Bevor wir darüber sprechen, möchte ich Ihnen zunächst eine kleine Beschreibung des Laravel-Frameworks geben.
Laravel ist ein in PHP geschriebenes Open-Source-Webframework, das das Model-View-Controller-Prinzip respektiert und vollständig in objektorientierter Programmierung entwickelt wurde.
Beispiel 1
Hier ist ein Beispiel für eine anfällige SQL-Anforderung in einem Laravel :
$user = DB::select('select * from users where username='. $request->post('username').' AND password='. $request->post('password'));
Das Laravel-Framework bietet einige großartige Funktionen, mit denen Entwickler die SQL-Anforderung vor böswilligen Injektionen schützen können. Leider hängen die meisten SQL-Injection-Schwachstellen, die ich in solchen Apps entdecke, mit dem Missbrauch von Laravel-Funktionen zusammen.
Lassen Sie uns das vorherige Beispiel analysieren, gemäß der Laravel-Dokumentation könnte die Funktion DB ::select zwei Parameter empfangen. Die erste ist die SQL-Anforderung und die zweite sind die Parameter. Um die Parameter für die SQL-Injektion zu filtern, müssen Sie die Parameter mit dem zweiten Parameter wie in diesem Beispiel in die Anforderung einfügen:
$user = DB::select(‘select * from users where username=? UND Passwort=?’, );
Beispiel 2
Laravel hat mehrere Möglichkeiten, mit der Datenbank zu kommunizieren In diesem Beispiel werden Sie sehen, dass Laravel den Entwickler zwingt, einige Funktionen zu verwenden, die die Benutzerdaten automatisch filtern, wie im folgenden Beispiel:
Users::where('username', $request->get('username'))->orderBy($request->get('orderby'))->get();
Diese Funktion soll gegen SQL-Injection gesichert sein, und das einzige Problem liegt auf der Funktionsebene OrderBy() . Laut Laravel-Dokumentation filtert diese Funktion die Benutzerdaten nicht, sodass ein SQL-Injection-Angriff über diese Funktion weiterhin möglich ist.
Das Beste ist, dem Benutzer nicht die Möglichkeit zu geben, den Tabellennamen zu steuern, aber wenn dies unvermeidlich ist, müssen Sie eine Whitelist verwenden, um die Benutzerdaten zu validieren, bevor Sie sie in diese Funktion einfügen.
Wie kann ein SQL-Injection-Angriff in Symfony verhindert werden?
Sehen wir uns ein weiteres bekanntes PHP-Framework an, das eine Reihe wiederverwendbarer PHP-Komponenten bietet, um die Entwicklung von PHP-Apps zu beschleunigen. Symfony wird auch von einigen der bekanntesten Web-CMS wie Drupal und Magento verwendet.
Symfony ist eines der sichersten Frameworks, mit dem Sie arbeiten können.Es bietet eine Vielzahl von Funktionen zum Schreiben eines sicheren Codes. Wenn diese Funktionen jedoch nicht gut genutzt werden, erhalten Sie einen anfälligen Code. Hier ist ein Beispiel für einen anfälligen Code:
$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery('SELECT p
FROM App\Entity\Product p
WHERE p.price > '. $request->query->get('price')
);
Lassen Sie uns nun diesen anfälligen Code analysieren. Gemäß der Symfony-Dokumentation ist createQuery () eine Funktion, die standardmäßig die vorbereiteten Anweisungen verwendet. Das aus einer solchen Funktion resultierende Objekt gibt Ihnen also Zugriff auf die Funktion setParameter(). Dieser filtert alle Benutzerdaten, um eine SQL-Injection zu vermeiden. Hier ist ein Beispiel, wie man es benutzt :
$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);
Wie kann ein SQL-Injection-Angriff in Codeigniter verhindert werden?
CodeIgniter eines der leistungsstärksten, leichtesten und beliebtesten PHP-Frameworks mit sehr geringem Platzbedarf. Es wurde für Entwickler entwickelt, die ein einfaches und elegantes Toolkit benötigen, um Webanwendungen mit vollem Funktionsumfang zu erstellen. Wie Symfony und Laravel enthält Codeigniter auch einige Sicherheitssysteme, mit denen Entwickler sicherere Apps erstellen können.
Aber auch bei Codeigniter machen einige Entwickler den gleichen Fehler und injizieren die Benutzerdaten ohne Filterung. Hier ist ein Beispiel für solche Fehler, die zu einem SQL-Injection-Angriff führen:
$query = 'SELECT * FROM users WHERE username = '. $this-> input->post('username'). ' AND password= '. $this-> input->post('password');
$this->db->query($query);
Um dieses Problem zu beheben, müssen Sie sich die Codeigniter-Dokumentation ansehen. Demnach nimmt die Funktion query () zwei Parameter an. Die erste ist die SQL-Abfrage und die zweite sind die Parameter, die Sie binden möchten.
Beispiel 1
Standardmäßig filtert diese Funktion alle gebundenen Parameter, um SQL-Injections zu verhindern. Hier ist ein Beispiel für die korrekte Verwendung dieser Funktion:
$query = 'SELECT * FROM users WHERE username = ? AND password = ? ';
$this->db->query($query, array($this->input->post('username'), $this-> input-> post('password')));
Beispiel 2:
Codeigniter bietet eine andere Möglichkeit zum Ausführen von SQL-Anforderungen, um SQL-Injektionen zu verhindern. Hier ist ein Beispiel für die Verwendung der Active Record-Klasse, um SQL-Injektionen zu verhindern:
$this->db->get_where('users',array('username'=>$this->input->post('username') ,'password' => $this->input->post('password')));
Wie verhindert man einen SQL-Injection-Angriff in CakePHP?
CakePHP ist ein schnelles Entwicklungsframework für PHP, das allgemein bekannte Entwurfsmuster wie assoziatives Datenmapping, Front Controller und MVC verwendet. CakePHP bietet eine Reihe von integrierten Komponenten, um die Entwicklung von Webanwendungen zu erleichtern und sie sicherer zu machen.
CakePHP-Apps sind jedoch auch anfällig für SQL-Injektionen, wenn sie nicht gut verwendet werden. Hier ist ein Beispiel für einen anfälligen Code für SQL-Injection-Angriffe in diesem Framework:
$results = $connection-> execute('SELECT * FROM users WHERE username = '. $this->request->getParam('username').' AND password='. $this->request->getParam('password'))->fetchAll('assoc');
Die Funktion execute() verwendet standardmäßig die vorbereiteten Anweisungen. Das vorherige Beispiel ist jedoch immer noch anfällig für SQL-Injection-Angriffe, da die Benutzerdaten direkt in eine legitime SQL-Anforderung eingefügt werden. Hier ist ein Beispiel für die richtige Verwendung dieser Funktion:
$results = $connection->execute('SELECT * FROM users WHERE username = :username AND password=:password', )->fetchAll('assoc');
Das CakePHP-Framework bietet auch ein System namens Query Builder, das die Filterung von Benutzerdaten erzwingt, um SQL-Injection-Angriffe zu verhindern. Gemäß der CakePHP-Dokumentation verwendet der Abfrage-Builder unter den Deckblättern die vorbereiteten Anweisungen.
Hier ist ein Beispiel, wie Sie ein solches System richtig verwenden können:
use Cake\ORM\Locator\LocatorAwareTrait;
$users = $this->getTableLocator()->get('users');
// Start a new query.
$query = $users->find();
$query->where();
Wie kann ein SQL-Injection-Angriff in FuelPHP verhindert werden?
FuelPHP ist eines der neuesten PHP-Frameworks, das auf den besten Ideen jedes Frameworks auf dem Markt basiert. Es wurde mit PHP 5 entwickelt und ist vollständig objektorientiert. In FuelPHP stand die Sicherheit im Vordergrund, was die Mitwirkenden dazu veranlasste, viele Sicherheitsmechanismen zum Filtern von Benutzerdaten zu implementieren. SQL Injection ist einer der Gründe, solche Mechanismen in FuelPHP zu implementieren.
Selbst bei einem so leistungsfähigen Framework gefährdet ein einfacher Missbrauch dieser Mechanismen den gesamten Code für einen SQL-Injection-Angriff. Hier ist ein Beispiel für einen solchen Codefehler:
$query = "SELECT * FROM article WHERE id = ". Input::get('id');
$result = DB::query($query)->execute();
Um dies zu beheben, gibt es auch zwei Techniken wie die anderen Frameworks. Die erste besteht darin, die Funktion query () korrekt zu verwenden, indem Sie die Parameter wie im folgenden Beispiel binden :
$query = "SELECT * FROM article WHERE id = :id"; // our query
$result = DB::query($query)->bind('id', Input::get('id'))->execute();
Die zweite Lösung besteht darin, den im FuelPHP-Framework implementierten ORM-Mechanismus für die Kommunikation mit der Datenbank zu verwenden. Hier ist ein Beispiel, wie man es benutzt:
$user = DB::select()->from('article')->where('id', Input::get('id'))->execute();
Wie kann man SQL Injection Angriffe im zend Framework verhindern?
Zend Framework (geändert in Laminas Project) ist eines der bekanntesten Frameworks in der Welt von PHP. Es wurde mit Blick auf die Leistungsoptimierung entwickelt, was erklärt, warum jede neue Version viel schneller ist als die alte. Zend wurde auch mit den besten Sicherheitspraktiken entwickelt, die seine Entwickler dazu drängten, zusätzliche Sicherheitsmechanismen zu implementieren, um mit bekannten Cyberbedrohungen umzugehen.
Einige dieser Mechanismen wurden implementiert, um mit den SQL-Injection-Angriffen umzugehen. Aber wie immer führt ein Missbrauch dieser Mechanismen zu einem anfälligen Code. In diesem Teil des Artikels werde ich ein Beispiel für einen solchen Fehler zeigen:
$adapter->query('SELECT * FROM `article` WHERE `id` = '. $this->getRequest()->getPost('id'));
So beheben Sie diese Sicherheitsanfälligkeit:
$adapter->query('SELECT * FROM `article` WHERE `id` = ?', );
Leave a Reply