© Malchev/Shutterstock.com
Besonders alte Versionen bergen Risiken

PHP 5.x und PHP 7.x - Sicherheit im Fokus!


Seit dem Ende des Jahres 2018 wird PHP 5.x nicht mehr unterstützt. Das heißt insbesondere: Jede seit Anfang Januar 2019 entdeckte Schwachstelle ist und bleibt eine Zero-Day-Schwachstelle – es wird keinen Patch dafür geben. Aber wie sieht es sonst noch so mit der Sicherheit von PHP 7.x im Vergleich zu PHP 5.x aus?

Im PHP Magazin 5.2013 habe ich über die Entwicklung der Sicherheit von PHP im Lauf der Zeit berichtet [1]. Zwei herausragende Entwicklungen damals: In PHP 5.5 wurde ein API zum Berechnen von Passwort-Hashes eingeführt und die klassische MySQL-Erweiterung [2] wurde als Deprecated, also überholt gebrandmarkt. Inzwischen ist sie Geschichte: In PHP 7.0 wurde sie entfernt. Weshalb ich damit auch anfangen möchte.

MySQL ist tot, es lebe MySQLi!

Wenn Sie die MySQL-Erweiterung verwendet haben, mussten Sie zu MySQLi [3] oder PDO_MySQL [4] wechseln (oder sich eine andere Datenbank suchen, aber das wird wohl kaum jemand getan haben). Das geht im Fall von MySQLi recht einfach und ich hoffe, Sie haben diesen einfachen Weg nicht genommen. Oder sind zumindest danach noch einen Schritt weiter gegangen.

Von MySQL zu MySQLi – Der leichte Weg

Wenn Sie eine Datenbankabfrage mit der MySQL-Erweiterung wie z. B. in Listing 1 in eine Abfrage mit MySQLi umwandeln wollen ändert sich wenig:

  • Beim Aufbau der Verbindung zum Datenbankserver geben Sie bei MySQLi auch gleich die gewünschte Datenbank an, die in der MySQL-Erweiterung separat ausgewählt wurde.

  • Alle mysql_-Aufrufe werden zu entsprechenden mysqli_-Aufrufen.

Das Ergebnis (Listing 2) sieht doch sehr ähnlich aus, die Änderungen halten sich in überschaubaren Grenzen und sind relativ schnell erledigt, oft reicht dazu ja Suchen und Ersetzen aus. Der Code in Listing 2 ist genauso sicher oder unsicher wie der in Listing 1, denn seine Sicherheit hängt einzig und allein davon ab, dass der Wert des Parameters $ort keinen SQL-Injection-Angriff enthält. Solange $ort nicht von einem möglichen Angreifer manipuliert werden kann oder die Eingabe dafür korrekt gefiltert oder maskiert wurde, besteht keine Gefahr. Ist das nicht der Fall, ergeben beide Listings eine wunderbare SQL-Injection-Schwachstelle.

Listing 1: Datenbankabfrage mit der MySQL-Erweiterung

// Verbindung zum MySQL-Server herstellen $connection = mysql_connect($dbserver,$dbuser,$dbpassword); if ($connection) {  // Verbindung zum MySQL-Server besteht  // Datenbank auswählen $db = mysql_select_db($dbname); if ($db) { // Verbindung zur Datenbank besteht // Daten abfragen $query = "SELECT benutzername FROM benutzer_tabelle WHERE ort = '".$ort."'"; $result = mysql_query($query); if ($result) {  // Abfrage erfolgreich while( $row = mysql_fetch_array($result) ) {  // Daten ausgeben oder sonstwie verarbeiten  // ... } } else {  // Fehler beim Holen der Daten echo "Fehler beim Holen der Daten: <br>\n"; echo "MySQL-Fehler: ".mysql_errno().": ".mysql_error()."<br> \n"; } } else {  // Keine Verbindung zur Datenbank echo "Fehler bei der Verbindung mit der Datenbank:<br> \n"; echo "MySQL-Fehler: ".mysql_errno().": ".mysql_error()."<br> \n"; } } else {  // Keine Verbindung zum MySQL-Server echo "Fehler bei der Verbindung mit dem MySQL-Server:<br> \n"; echo "MySQL-Fehler: ".mysql_errno().": ".mysql_error()."<br> \n"; }

Listing 2: Datenbankabfrage mit der MySQLi-Erweiterung

// Verbindung zur Datenbank herstellen $db = mysqli_connect($dbserver, $dbuser, $dbpassword, $dbname); if ($db) {  // Verbindung zur Datenbank besteht  // Daten abfragen $query = "SELECT benutzername FROM benutzer_tabelle WHERE ort = '".$ort."'"; $result = mysqli_query($db, $query); if ($result) {  // Abfrage erfolgreich while( $row = mysqli_fetch_array($result) ) {  // Daten ausgeben oder sonstwie verarbeiten   // ... } } else {  // Fehler beim Holen der Daten echo "Fehler beim Holen der Daten: <br>\n"; echo "MySQL-Fehler: ".mysqli_errno().": ".mysqli_error()."<br> \n"; } } else {  // Keine Verbindung zu MySQL echo "Fehler bei der Verbindung mit dem MySQL-Server:<br> \n"; echo "MySQL-Fehler: ".mysqli_connect_errno().": ".mysqli_connect_error()."<br> \n"; }

Prepared Statements mit Parameter Binding verhindern SQL Injection

Einen zuverlässigen Schutz vor SQL Injection bieten parametrisierte Aufrufe von Prepared Statements oder Stored Procedures, was auch als Parameter Binding oder Parameterized Queries bezeichnet wird. Dabei wird der Aufbau des SQL-Statements in zwei Schritte aufgespalten:

  1. Die Struktur des SQL-Statements wird definiert, für alle Eingaben werden Platzhalter eingesetzt.

  2. Der Inhalt der Platzhalter wird spezifiziert.

Die im zweiten Schritt eingefügten Daten haben keine Möglichkeit, die im ersten Schritt definierte Struktur des Statements zu ändern. Nachdem die Struktur des Statements definiert wurde, werden alle für die Platzhalter übergebenen Daten als Daten und nicht als Teil der Statementstruktur betrachtet. Schleust ein Angreifer SQL-Code ein, wird er nicht ausgeführt. Während in Listing 1 und Listing 2 eine Eingabe wie z. B.

Irgendwo’ OR 1=1

zur Ausgabe sämtlicher Benutzernamen führt, würde bei einem parametriesierten Aufruf eines Prepared Statements nichts ausgegeben. Es sei denn, in der Spalte ort gäbe es einen...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang