In diesem Kapitel lernst du, wie Angreifer durch geschickte Manipulation von Nutzereingaben in Webformularen Zugriff auf Datenbanken erlangen können. Dies funktioniert, wenn die Software, die die Eingaben verarbeitet, nicht sorgfältig genug programmiert wurde. Dazu werden wir uns zuerst eine neue Datenbank für unser Experiment anlegen, die wir dann mit einigen Testdaten füllen.
Erstelle eine neue Datenbank in deinem Workspace-Profil und kopiere den Namen der Datenbank in die Zwischenablage, da wir ihn später benötigen werden. In diesem Tutorial werden wir die Datenbank db_1234
nennen – ersetze diese Bezeichnung
also immer durch den Namen deiner Datenbank.
Öffne ein Terminal im Workspace und gib den folgenden Befehl ein, um die Testdaten herunterzuladen:
wget https://github.com/specht/workspace-files/raw/main/users.sql
Importiere die Testdaten in deine Datenbank (achte darauf, dass du den Namen deiner neuen Datenbank angibst):
mycli db_1234 < users.sql
Starte anschließend mycli
und überprüfe mit Hilfe von SHOW TABLES
und einem SELECT
-Statement, ob die Daten korrekt importiert wurden:
login | password | address |
---|---|---|
admin | YLrelnmPDPB-ZhQ1GzRxiEf | 2683 John Calvin Drive, Chicago IL 60603 |
alice | asdf | 578 Gordon Street, Claremont CA 91711 |
bob | 1234 | 525 Cambridge Drive, Phoenix AZ 85039 |
mallory | hunter2 | 3747 Haven Lane, Lansing MI 48933 |
Erstelle eine neue Datei login.rb
und füge den folgenden Ruby-Code ein:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
require 'tty-prompt' require 'mysql2' PROMPT = TTY::Prompt.new CLIENT = Mysql2::Client.new( host: ENV['MYSQL_HOST'], username: ENV['MYSQL_USER'], password: ENV['MYSQL_PASSWORD'], database: 'db_1234' ) login = PROMPT.ask('Login:') password = PROMPT.ask('Password:') rows = CLIENT.query("SELECT login FROM users \ WHERE login = '#{login}' \ AND password = '#{password}' LIMIT 1;").to_a if rows.empty? puts "❌ Fehler: Ungültige Zugangsdaten!" else user = rows.first['login'] puts "✅ Anmeldung erfolgreich." puts "Herzlich willkommen, #{user}." end |
Hinweise:
#{ ... }
können Variablen in Strings eingebettet werden (Z. 16 und 17) – genauso wie z. B. in Python mit f-Strings. Man nennt diese Technik auch String Interpolation.Notiere dir die SQL-Statements, die aus den folgenden Aufgaben hervorgehen, weil du sie später benötigen wirst.
#
oder --
eingefügt werden, die bis zum Ende der Zeile gelten und nicht ausgeführt werden.
mallory' UNION SELECT address FROM users WHERE LOGIN='mallory' ORDER BY login ASC #
Wie du siehst, kann es gefährlich werden, wenn man Nutzereingaben blind vertraut. Es ist daher bei sicherheitskritischen Systemen notwendig, alle Eingaben mit einer gesunden Portion Misstrauen zu betrachten. Das Problem liegt hier auf der Seite der Software, die solche Angriffe zulässt.
Der Angriffsmechanismus, den wir hier verwendet haben, heisst »SQL Injection«, weil ein Angreifer eigenen SQL-Code in eine SQL-Abfrage einschleust und somit das Programm dazu zwingen kann, andere Dinge zu tun, als ursprünglich vorhergesehen waren. Wir können die Sicherheitslücke leicht schließen, indem wir verhindern, dass Nutzereingaben direkt in die SQL-Abfrage eingefügt werden. Anstatt die Eingabe über String Interpolation direkt einzubinden, können wir ein »Prepared Statement« verwenden. Hierbei wird eine SQL-Abfrage mit Platzhaltern vorbereitet, die dann mit den Nutzereingaben ausgeführt wird. Der SQL-Code wird also nicht direkt mit den Nutzereingaben vermischt, sondern getrennt behandelt.
Kommentiere die Zeilen 15 bis 17 aus und füge dahinter die folgenden Zeilen ein:
query = CLIENT.prepare("SELECT login FROM users WHERE login = ? AND password = ? LIMIT 1;") rows = query.execute(login, password).to_a
#
beginnen lässt. Schneller geht es, wenn du die Zeilen markierst und dann Strg# drückst (bzw. Ctrl/, falls du ein US-Tastaturlayout verwendest).
Das Eindringen in fremde Computersysteme bzw. das Auspähen von Daten ist illegal und wird bestraft. Die hier gezeigten Beispiele dienen ausschließlich der Demonstration von Sicherheitslücken und sollen dazu beitragen, dein Bewusstsein für die Gefahren bei der Programmierung von Software und der Verarbeitung von Nutzereingaben zu schärfen. Es ist wichtig, dass du dein Wissen verantwortungsbewusst einsetzt und nur auf Systemen experimentierst, für die du die ausdrückliche Erlaubnis hast oder die du selbst betreibst.
Der Zweck dieses Tutorials ist es also nicht, dich dazu zu ermutigen, in fremde Systeme einzudringen oder Daten zu stehlen, sondern dir zu zeigen, worauf du achten musst, um solche Angriffe zu verhindern, wenn du Software implementierst.
Ein kleiner Vergleich zum Schluß: Es ist in Ordnung, wenn du deine Fähigkeiten und ein Lockpicking-Set verwendest, um deine eigenen Schlösser zu öffnen, weil du z. B. den Schlüssel verloren hast. Sobald du allerdings fremde Schlösser ohne Erlaubnis öffnest, begehst du eine Straftat.
Cartoon von Randall Munroe, xkcd.com.