Lässt es sich mit cremefarbenem Papier, einer Tönung, mehr Kontrast oder größerer Schrift besser lesen? Wählen Sie Ihre Farben und Ihre Schrift, einmalig für alle Seiten.

Kostenlose Lektion

SQL-Injection: Text, der eine Abfrage verändert

Nach dieser Lektion: Ich kann eine Abfrage so bauen, dass eingetippter Text sie nicht verändern kann.

Lektion, 55 Min.3 BefehleSQL-Injection-Lab: eine schwache Shop-Suche angreifen, die Abfrage reparieren und die Reparatur belegen

Eine Shop-Suche zeigt einen Fehler

Ein kleiner Shop hat ein Suchfeld für seine Artikelliste. Ein Besucher tippt ein Wort mit Apostroph ein, zum Beispiel O'Brien.

Die Seite antwortet mit einer Zeile fremder Wörter aus der Maschine dahinter. Der Inhaber nennt das einen kleinen Fehler. Es ist ein Zeichen: Die Seite lässt Besucher einen Teil ihrer Fragen selbst schreiben.

Die eine Regel

Warnung

Dieses Lab ist ein Shop, der absichtlich unsicher ist. Greifen Sie nur Ihre eigene, private Kopie an und nichts sonst. Sie hat keine Verbindung ins Internet. Dieselben Versuche bei einem fremden System sind eine Straftat. Das gilt auch dann, wenn Sie nichts beschädigen wollen.

Am Ende dieser Lektion

Notiz

Ich kann eine Abfrage so bauen, dass eingetippter Text sie nicht verändern kann.

Schlüsselwörter

BegriffWas er bedeutetBeispiel
Datenbankein geordneter Speicher für Datensätze, den ein Programm befragen kann
Abfrageeine Frage, die ein Programm an eine Datenbank stellt; auf Englisch QuerySELECT name FROM produkte
SQL-Injectioneingetippter Text, der die Abfrage eines Programms verändert
Parameterein Wert, der neben der Abfrage gesendet wird und nie darin steht?
Zeichenketteein Stück Text in einem Programm; auf Englisch String"Stift"
Eingabealles, was ein Besucher an eine Seite tippt oder sendet

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Eine zusammengesetzte Abfrage lässt sich ändern

Viele Programme bauen eine Abfrage, indem sie einen festen Anfang mit dem Text des Besuchers verbinden. Die Datenbank bekommt eine lange Zeichenkette. Sie kann nicht erkennen, welcher Teil vom Programmierer stammt und welcher vom Besucher.

Enthält der Text ein Anführungszeichen, beendet es den Text des Programmierers zu früh. Was danach kommt, liest die Datenbank als Teil der Abfrage.

Die Abfrage, die das Programm baut

Code: python
# Ändern Sie begriff in "Notizbuch" und führen Sie den Block aus.
# Probieren Sie danach "Rock'n'Roll".
begriff = "Stift"
anfang = "SELECT name, preis FROM produkte WHERE name LIKE '%"
abfrage = anfang + begriff + "%'"
print(abfrage)

Beispiel: drei Suchen

Der Besucher tipptDie Datenbank erhältWas passiert
Stift... LIKE '%Stift%'Funktioniert wie gedacht
Rock'n'Roll... LIKE '%Rock'n'Roll%'Das erste Apostroph beendet den Text zu früh, die Abfrage ist kaputt
x' AND 1=2 --... LIKE '%x' AND 1=2 --%'Der Besucher hat eine eigene Bedingung eingefügt

Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.

Der Shop in Ihrem Lab

Ihr Lab enthält einen echten Shop mit dieser Schwäche. Starten Sie das Lab und führen Sie dann diese drei Befehle aus. Sie sehen nur hin. Der erste ist eine normale Suche. Der zweite sucht einen Namen mit Apostroph, den der Shop nicht verarbeiten kann. Der dritte zeigt die Codezeile des Shops, die die Abfrage baut.

Eine normale Suche

Befehl
curl -s -G --data-urlencode "q=pen" http://app:8000/search

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Ein Name mit Apostroph

Befehl
curl -s -G --data-urlencode "q=Baker's" http://app:8000/search

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Die Zeile, die die Abfrage baut

Befehl
docker exec app grep -n "rows = db.execute" /tmp/app/app.py

Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.

Was die drei Ausgaben sagen

Die erste gibt Pen 1.2 aus, also Name und Preis. Die zweite gibt eine Zeile aus, die mit database error beginnt. Der Shop hat Ihr Apostroph direkt in seine Abfrage übernommen.

Die dritte gibt eine Zeilennummer und eine lange Codezeile aus. Suchen Sie die +-Zeichen darin. Jedes verbindet eingetippten Text mit der Abfrage.

Ein Parameter hält Text aus der Abfrage heraus

Ein Parameter behebt das. Das Programm sendet die Abfrage mit einem Platzhalter ? an der Stelle des Werts, als vorbereitete Anweisung (Prepared Statement). Den eingetippten Text sendet es getrennt.

Die Datenbank liest zuerst die Abfrage und legt ihre Form fest. Der Text kommt später und kann nur noch ein Wert sein. Kein Anführungszeichen darin kann etwas beenden.

Dieselbe Suche mit Parameter

Code: python
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE produkte (name TEXT, preis REAL)")
db.execute("INSERT INTO produkte VALUES (?, ?)", ("Rock'n'Roll-Tasse", 8.5))
db.execute("INSERT INTO produkte VALUES (?, ?)", ("Stift", 1.2))
# Ändern Sie begriff und führen Sie den Block aus.
# Nichts, was Sie tippen, kann die Abfrage vorzeitig beenden.
begriff = "Rock'n'Roll"
zeilen = db.execute("SELECT name, preis FROM produkte WHERE name LIKE ?", ("%" + begriff + "%",)).fetchall()
print(zeilen)

Ein häufiger Fehler

Warnung

Viele glauben, es genüge, das Apostroph aus dem Text zu entfernen. Das stimmt nicht. Filter übersehen Fälle, und jeder übersehene Fall ist eine Lücke. Ein Parameter wirkt, weil er Text nie in die Abfrage mischt, egal wie raffiniert der Text ist. Nutzen Sie für jeden Wert einen Parameter.

Manches kann kein Parameter sein

Ein Parameter kann für einen Wert stehen. Er kann nicht für einen Spaltennamen oder eine Sortierung stehen. Lässt eine Seite Besucher nach Preis oder Name sortieren, muss das Wort trotzdem in die Abfrage.

Sicher ist eine kurze Liste erlaubter Wörter. Steht die Wahl des Besuchers nicht darauf, gilt ein Standardwert.

Nur Wörter aus der Liste

Code: python
ERLAUBT = ["name", "preis"]
# Ändern Sie wahl auf "preis", dann auf "lager; weg", und führen Sie den Block aus.
wahl = "name"
if wahl in ERLAUBT:
    spalte = wahl
else:
    spalte = "name"
print("ORDER BY " + spalte)

Über dieses Lab und seinen Quellcode: SQL-Injection-Lab: eine schwache Shop-Suche angreifen, die Abfrage reparieren und die Reparatur belegen

Sie unterrichten eine Gruppe? Weisen Sie dieses Modul Ihren Studierenden zu, mit Handbuch für Lehrende, automatisch geprüften Aufgaben und einem Lab für jede Person.