PHP-Einfach.de
  • PHP Tutorial
  • MySQL Tutorial
  • Für Fortgeschrittene
  • Webhosting
  • Forum

SQL-Injections

10. Februar 2020
  1. Home
  2. »
  3. Für Fortgeschrittene
  4. »
  5. PHP Sicherheit
  6. »
  7. SQL-Injections

SQL-Injections bezeichnet das Ausnutzen von Sicherheitslücken im Zusammenhang mit SQL-Datenbanken, die durch mangelnde Überprüfung von Eingabeparameter entstehen. Diese Art der Sicherheitslücke zählt zu eine der häufigsten und ist oftmals besonders kritisch, da Angreifer so an sensible Daten eurer Nutzer gelangen können. Wie bei den meistens anderen Sicherheitslücken auch gilt bei SQL-Injections der Merkspruch: Traue niemals den Eingaben von Benutzern.

Inhaltsverzeichnis

  • 1 Grundlagen SQL-Injections
  • 2 Schutz vor SQL-Injections
  • 3 Validierung von Eingaben

Grundlagen SQL-Injections

Um die Angriffe und den Schutz zu verdeutlichen Nutzen wir nachfolgenden die User-Tabelle aus unserem MySQL Tutorial (weitere Infos).

Ein häufiger Fehler vieler Programmierung ist die falsche Dynamisierung von SQL-Queries. Einem Script wird ein gewisser Wert übergeben, beispielsweise mittels GET-Parameter eine ID. Um nun den Datensatz mit der entsprechenden ID abzufragen wird oft ein Code wie folgt verwendet:

Der einfachste Gedanke wäre wie folgt (diese Variante ist nicht zu empfehlen):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$pdo = new PDO('mysql:host=localhost;dbname=databasename', 'username', 'password');
 
if(isset($_GET['id'])) {
   $id = $_GET['id'];
} else {
   die("Bitte eine ?id übergeben");
}
 
$sql = "SELECT email, vorname, nachname FROM users WHERE id = $id";
foreach ($pdo->query($sql) as $row) {
   echo $row['vorname']." ".$row['nachname']."<br />";
   echo "E-Mail: ".$row['email']."<br /><br />";
}
?>

Das Problem liegt hier in Zeile 10. Ruft ihr die Seite mit folgendem Parameter auf:
seite.php?id=1 OR id > 1

So wird der folgende SQL Befehl erzeugt und an die Datenbank gesendet:

1
SELECT email, vorname, nachname FROM users WHERE id = 1 OR id > 1

Das Resultat davon ist die Ausgabe aller Benutzer statt nur einem einzelnen Nutzer.  Dies mag vielleicht nun nicht so tragisch sein, aber ein Angreifer kann nun viel Unfug treiben. Der Aufruf der Seite mittels:
seite.php?id=-1 UNION SELECT email, vorname, passwort AS nachname FROM user

Daraus wird der folgende SQL-Query gebaut und an die Datenbank gesendet:

1
SELECT email, vorname, nachname FROM users WHERE id =-1 UNION SELECT email, vorname, passwort AS nachname FROM user

Mittels der UNION-Anweisung werden zwei SQL-Queries miteinander verbunden. Der erste Query versucht die Information für den Nutzer '-1' zu finden, der nicht existiert. Der zweite Query fragt erneut eure User-Tabelle ab, aber in diesem Fall wird das Passwort-Feld umbenannt in das Nachname-Feld. Der nachfolgende Script, der ja den harmlosen Nachnamen ausgibt, gibt nun alle E-Mail-Adressen, Vornamen und Passwörter eurer User aus.

Durch diese SQL-Injection kann ein Angreifer an sämtliche Daten eurer Datenbank gelangen.

Nicht nur SELECT-Anweisungen sind gefährdet, sondern sämtliche Daten die ihr an die Datenbank sendet. So können auch UPDATE, INSERT und DELETE-Anweisungen entsprechend manipuliert werden. Habt ihr beispielsweise den folgenden SQL-Query:

1
$sql = "UPDATE user SET vorname='".$_POST['neuer_vorname']."' WHERE id = ".$_SESSION['userid'];

Hier kann ein Angreifer zwar nicht unbedingt die Session manipulieren, aber dieser kann den Wert von neuer_vorname manipulieren. Gibt er im Formularfeld beispielsweise folgenden Wert ein:

1
You got hacked', passwort='Hacker Passwort' WHERE id=1 --

So sieht der an die Datenbank gesendete SQL-Query wie folgt aus (angenommen der Angreifer hat die User-ID 374):

1
UPDATE user SET vorname='You got hacked', passwort='Hacker Passwort' WHERE id=1 -- ' WHERE id = 374

Die zwei Bindestriche -- kommentieren die nachfolgenden Anweisungen aus. Mit solch einer Eingabe lässt sich der Vorname und das Passwort von beliebigen Benutzern in eurer User-Tabelle verändern. So kann der Angreifer beispielsweise das Passwort von einem Administrator überschreiben und erhält dadurch Zugriff auf einen Administratoraccount, womit weiterer Schaden angerichtet werden kann.

Schutz vor SQL-Injections

Der beste Schutz vor SQL-Injections ist mittels Prepared Statements gegeben. Bei prepared Statements werden die Parameter, im den obigen Beispielen die ID oder der neue Vorname, seperat vom SQL-Query an die Datenbank gesendet. Dadurch ist gewährleistet, dass eingeschleuster Code in die Variable keinen Effekt auf den Query hat.

Es ist stark zu empfehlen, jede Query mit Nutzerdaten als Prepared Statement auszuführen. Versucht nicht in Versuchung zu kommen den SQL-Query selber zu konstruieren, da dies Fehleranfällig ist. Durch die (richtige) Verwendung von Prepared Statements seid ihr gegen SQL-Injections geschützt.

 

Validierung von Eingaben

Nach eigener Erfahrung lassen sich 98% der Queries mittels Prepared Statements konstruieren und sind somit sicher für SQL-Injections. Ein paar spezielle Queries existieren dennoch, bei denen man nicht auf Prepared Statements zurückgreifen kann. Möchte man dem Besucher z.B. erlauben eine Tabelle basierend auf frei wählbare Spalten zu durchsuchen, so steckt das dynamische Element in der Struktur des Queries und nicht im Parameter.

Eine unsichere Variante für solch eine Suchfunktion wäre:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
 
$suchspalte = $_GET['suchspalte']; //z.B. die Spalte vorname
$suchwort = $_GET['suchwort']; //z.B. den Namen Max
 
$statement = $pdo->prepare("SELECT * FROM users WHERE ".$suchspalte." LIKE :vorname");
$statement->execute(array(':vorname' => "%$suchwort%"));  
while($row = $statement->fetch()) {
   echo $row['vorname']." ".$row['nachname']."<br />";
   echo "E-Mail: ".$row['email']."<br /><br />";
}
?>

Der Parameter suchwort ist zwar vor SQL-Injections geschützt, aber über den Parameter suchspalte kann ein Angreifer beliebigen Schaden anrichten. Dieses per Prepared Statement abzusichern ist leider nicht möglich. Deswegen müssen wir entweder fixe SQL-Queries nutzen oder den Wert von $suchspalte entsprechend validieren.

Eine sichere Variante ist die folgende:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
 
$suchspalte = $_GET['suchspalte']; //z.B. die Spalte vorname
$suchwort = $_GET['suchwort']; //z.B. den Namen Max
 
$erlaubte_spalten = array('vorname', 'nachname', 'email');
if(!in_array($suchspalte, $erlaubte_spalten)) {
   die('Ungültiger Parameter für $suchwort');
}
 
$statement = $pdo->prepare("SELECT * FROM users WHERE ".$suchspalte." LIKE :suchwort");
$statement->execute(array(':suchwort' => "%$suchwort%"));  
while($row = $statement->fetch()) {
   echo $row['vorname']." ".$row['nachname']."<br />";
   echo "E-Mail: ".$row['email']."<br /><br />";
}
?>

Hier wird ein Array mit erlaubten Werten erzeugt und nur wenn wir solch einen Wert vorliegend haben, wird das weitere Script ausgeführt. Falls ein Angreifer versuchen würde einen anderen Wert für $suchspalte zu übergeben, würde unser Script mittels der Funktion die() abbrechen.

Autor: Nils Reimers
Zurück: Penetrationtesting für PHP
Weiter: Script-Beispiele

Für Fortgeschrittene

  • Objektorientierte Programmierung
  • PHP Sicherheit
    • Authentifizierung in PHP
    • Code Injection
    • Cross-Site-Request-Forgery (CSRF)
    • Cross-Site-Scripting (XSS) in PHP
    • Daten sicher speichern
    • Daten validieren
    • Penetrationtesting für PHP
    • SQL-Injections
  • Script-Beispiele
  • Codeschnipsel
  • Stellenmarkt
Mit freundlicher Unterstützung von:
  • Punkt191 Werbeagentur

Hoster – Geringste Ausfallzeit

  1. netcup Ø 0 Min.
  2. webgo Ø 0 Min.
  3. Linevast Ø 3 Min.
  4. All-Inkl.com Ø 3 Min.
  5. checkdomain Ø 4 Min.
  6. dogado Ø 6 Min.
  7. Strato Ø 8 Min.
  8. manitu Ø 10 Min.
  9. 1&1 Ø 10 Min.
  10. DomainFactory Ø 14 Min.
» Mehr erfahren

Impressum | Datenschutz | Auf PHP-Einfach.de werben

© PHP-Einfach.de 2003 - 2025

Cookie-Zustimmung verwalten
Um dir ein optimales Erlebnis zu bieten, verwenden wir Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wenn du diesen Technologien zustimmst, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn du deine Zustimmung nicht erteilst oder zurückziehst, können bestimmte Merkmale und Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Anbieter verwalten Lese mehr über diese Zwecke
Einstellungen ansehen
{title} {title} {title}