Jeder, der MySQL auf einem mit dem Internet verbundenen Computer betreibt, sollte diesen Abschnitt lesen, um die häufigsten sicherheitsspezifischen Fehler zu vermeiden.
In unserer Beschreibung zur Sicherheit wollen wir die Notwendigkeit betonen, den gesamten Serverhost (und nicht nur den MySQL-Server) gegen alle möglichen Angriffe zu schützen: Lauschangriffe, Modifikationen, Wiedergabe und DoS (Denial of Service, Dienstablehnung). Wir werden an dieser Stelle nicht alle Aspekte der Verfügbarkeit und Fehlertoleranz behandeln.
MySQL benutzt ein Sicherheitssystem, welches auf ACLs (Access Control Lists, Zugriffssteuerungslisten) basiert, für alle Verbindungen, Abfragen und anderen Operationen, die Benutzer durchzuführen versuchen können. Ferner unterstützt werden SSL-verschlüsselte Verbindungen zwischen MySQL-Clients und -Servern. Viele der hier beschriebenen Konzepte sind keineswegs MySQL-spezifisch, sondern gelten vielmehr für fast alle gängigen Anwendungen.
Wenn Sie MySQL ausführen, befolgen Sie, sofern irgendwie möglich, die folgenden Richtlinien:
Gewähren Sie niemals irgendjemandem (mit Ausnahme von MySQL-root-Konten) Zugang zur Tabelle user in der mysql-Datenbank! Dies ist entscheidend. Das verschlüsselte Passwort ist das echte Passwort in MySQL. Jeder, der das Passwort kennt, welches in der Tabelle user aufgeführt ist, und Zugang zu dem für das betreffende Konto gelisteten Host hat, kann sich problemlos als dieser Benutzer anmelden.
Machen Sie sich mit dem MySQL-Zugriffsberechtigungssystem vertraut. Die Anweisungen GRANT und REVOKE werden zur Steuerung des Zugriffs auf MySQL verwendet. Gewähren Sie nie mehr Berechtigungen als notwendig. Gewähren Sie Berechtigungen niemals allen Hosts.
Checkliste:
Geben Sie mysql -u root ein. Wenn Sie mit dem Server erfolgreich eine Verbindung herstellen können, ohne nach einem Passwort gefragt worden zu sein, dann kann jede Person als MySQL-Benutzer root eine solche Verbindung mit Ihrem MySQL-Server herstellen und hat nachfolgend alle Berechtigungen! Lesen Sie noch einmal die MySQL-Installationsanleitung und achten Sie dabei insbesondere auf Informationen zur Einstellung eines root-Passworts. Siehe auch Abschnitt 2.9.3, „Einrichtung der anfänglichen MySQL-Berechtigungen“.
Überprüfen Sie mithilfe der Anweisung SHOW GRANTS, welche Konten worauf zugreifen können. Entfernen Sie dann nicht erforderliche Berechtigungen mit der REVOKE-Anweisung.
Speichern Sie Passwörter nicht unverschlüsselt in Ihrer Datenbank. Wenn der Computer in die Hände eines Angreifers fällt, kann dieser die Passwortliste lesen und die Passwörter verwenden. Verwenden Sie stattdessen MD5(), SHA1() oder eine andere unidirektionale Hashing-Funktion und speichern Sie den Hash-Wert.
Wählen Sie keine Passwörter aus Wörterbüchern aus. Es gibt Spezialprogramme zum Knacken von Passwörtern. Sogar Passwörter wie „fisch98“ sind ziemlich schlecht. Wesentlich besser ist „duaxg98“: Dieses Passwort enthält zwar auch das Wort „fisch“, jedoch wurde jeder Buchstabe auf einer QWERTZ-Standardtastatur durch die Taste zu seiner Linken ersetzt. Eine andere Methode, ein Passwort zu verwenden, besteht darin, die jeweils ersten Buchstaben jedes Wortes eines Satzes zu benutzen; so wird etwa aus „Hoch auf dem gelben Wagen“ ganz einfach das Passwort „HadgW“. Dieses Passwort ist vergleichsweise einfach zu merken und einzugeben, aber für jemanden, der den Satz gar nicht kennt, schwer zu erraten.
Schaffen Sie eine Firewall an. Diese schützt Sie vor mindestens 50 Prozent aller Sicherheitslücken in jeder beliebigen Software. Setzen Sie MySQL hinter die Firewall oder in eine DMZ (De-Militarized Zone, entmilitarisierte Zone).
Checkliste:
Scannen Sie Ihre Ports aus dem Internet heraus mithilfe eines Tools wie nmap. MySQL verwendet standardmäßig Port 3306. Dieser Port sollte für nicht vertrauenswürdige Hosts nicht zugänglich sein. Eine weitere einfache Möglichkeit zu prüfen, ob Ihr MySQL-Port offen ist oder nicht, besteht darin, den folgenden Befehl an einem entfernten System einzugeben. Hierbei ist server_host der Hostname oder die IP-Nummer des Hosts, auf dem Ihr MySQL-Server ausgeführt wird:
shell> telnet server_host 3306
Wenn Sie eine Verbindung erhalten und einige sinnlose Zeichen angezeigt werden, ist der Port geöffnet; Sie sollten ihn dann umgehend mit Ihrer Firewall oder Ihrem Router schließen, es sei denn, es gäbe einen guten Grund dafür, dass der Port offen ist. Wenn telnet hängt oder die Verbindung abgewiesen wird, dann ist der Port gesperrt – so soll es sein.
Schenken Sie Daten, die von Benutzern Ihrer Anwendungen eingegeben wurden, kein Vertrauen. Benutzer können Ihren Code überlisten, indem Sie Sonderzeichen oder Zeichenfolgen mit vorangestelltem Escape-Zeichen in Webformulare, URLs oder andere Eingabemöglichkeiten der von Ihnen erstellten Anwendungen eintragen. Sie müssen sicherstellen, dass Ihre Anwendung auch dann sicher bleibt, wenn ein Benutzer so etwas wie „; DROP DATABASE mysql;“ eingibt. Dies ist natürlich ein Extrembeispiel, aber große Sicherheitslücken oder umfangreiche Datenverlust können die Folge sein, wenn Hacker ähnliche Methoden verwenden und Sie nicht darauf vorbereitet sind.
Ein häufiger Fehler besteht darin, nur String-Datenwerte zu schützen. Denken Sie daran, auch numerische Daten abzusichern. Wenn eine Anwendung eine Abfrage wie SELECT * FROM table WHERE ID=234 erzeugt, weil ein Benutzer den Wert 234 eingegeben hat, dann kann der Benutzer auch den Wert 234 OR 1=1 eingeben; hierauf generiert die Anwendung die Abfrage SELECT * FROM table WHERE ID=234 OR 1=1. Folge ist, dass der Server jeden Datensatz in der Tabelle abruft. Mithin wird jeder Datensatz angezeigt, zudem wird der Server extrem belastet. Die einfachste Möglichkeit, sich vor diesem Angriffstyp zu schützen, besteht darin, numerische Konstanten in Anführungszeichen zu setzen: SELECT * FROM table WHERE ID='234'. Gibt nämlich der Benutzer zusätzliche Daten an, so werden sie alle Teil des Strings. In einem numerischen Kontext wandelt MySQL diesen String automatisch in eine Zahl um und entfernt alle nachfolgenden nichtnumerischen Zeichen.
Manche Leute gehen davon aus, dass eine Datenbank, die nur öffentlich verfügbare Daten enthält, nicht geschützt werden muss. Das stimmt nicht. Auch wenn jeder Datensatz in der Datenbank angezeigt werden dürfte, sollten Sie sich trotzdem etwa gegen DoS-Angriffe schützen (z. B. jene, die auf der im vorigen Absatz beschriebenen Methode basieren und den Server dazu bringen, Ressourcen zu vergeuden). Andernfalls kann Ihr Server für legitime Benutzer unerreichbar werden.
Checkliste:
Geben Sie einfache und doppelte Anführungszeichen (‘'’ bzw. ‘"’) in all Ihre Webformulare ein. Wird irgendein MySQL-Fehler ausgegeben, dann untersuchen Sie das Problem umgehend.
Versuchen Sie, dynamische URLs durch Hinzufügen von %22 (‘"’), %23 (‘#’) und %27 (‘'’) zu modifizieren.
Versuchen Sie, die Datentypen in dynamischen URLs von numerischen auf Zeichentypen umzustellen, indem Sie die in den obigen Beispielen verwendeten Zeichen eingeben. Ihre Anwendung sollte gegen solche und ähnliche Angriffe gewappnet sein.
Geben Sie Buchstaben, Leer- und Sonderzeichen statt Ziffern in numerische Felder ein. Ihre Anwendung sollte diese Zeichen entfernen, bevor Sie sie an MySQL übergibt, oder andernfalls einen Fehler erzeugen. Die Übergabe ungeprüfter Werte an MySQL ist extrem gefährlich!
Überprüfen Sie die Daten, bevor Sie sie an MySQL übergeben.
Lassen Sie Ihre Anwendung eine Verbindung mit der Datenbank unter Verwendung eines anderen Benutzernamens als desjenigen herstellen, den Sie für administrative Zwecke verwenden. Geben Sie Ihren Anwendungen nicht mehr Zugriffsberechtigungen als notwendig.
Viele APIs stellen eine Methode bereit, um Sonderzeichen in Datenwerten zu kennzeichnen. Richtig verwendet, verhindert dies, dass Anwendungsbenutzer Werte eingeben können, die eine Erzeugung von Anweisungen durch die Anwendung verursachen könnten, welche einen anderen Effekt als von Ihnen erwünscht hervorrufen:
MySQL-C-API: Verwenden Sie den API-Aufruf mysql_real_escape_string().
MySQL++: Verwenden Sie die Modifizierer escape und quote für Abfrage-Streams.
PHP: Verwenden Sie die Funktion mysql_escape_string(), die auf der gleichnamigen Funktion in der MySQL-C-API basiert. (Bei PHP vor Version 4.0.3 benutzen Sie stattdessen addslashes().) In PHP 5 können Sie die Erweiterung mysqli einsetzen, die das verbesserte MySQL-Authentifizierungsprotokoll und Passwörter ebenso unterstützt wie vorbereitete Anweisungen mit Platzhaltern.
Perl DBI: Verwenden Sie die Methode quote() oder Platzhalter.
Ruby DBI: Verwenden Sie Platzhalter.
Java JDBC: Verwenden Sie ein PreparedStatement-Objekt und Platzhalter.
Andere Programmierschnittstellen weisen möglicherweise ähnliche Funktionalitäten auf.
Übertragen Sie keine unverschlüsselten Daten über das Internet. Auf solche Daten kann jeder zugreifen, der die Zeit und die Fähigkeiten hat, sie abzufangen und für eigene Zwecke zu verwenden. Verwenden Sie stattdessen ein verschlüsseltes Protokoll wie SSL oder SSH. MySQL unterstützt interne SSL-Verbindungen ab Version 4.0. Eine andere Methode besteht in der Verwendung der SSH-Portweiterleitung, mit der man einen verschlüsselten (und komprimierten) Kommunikationstunnel einrichten kann.
Machen Sie sich mit den Hilfsprogrammen tcpdump und strings vertraut. In den meisten Fällen können Sie durch Absetzen eines Befehls wie des folgenden überprüfen, ob MySQL-Datenströme unverschlüsselt sind:
shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings
(Das funktioniert unter Linux und sollte mit kleinen Anpassungen auf unter anderen Betriebssystemen laufen.) Warnung: Wenn Sie keine Klartextdaten sehen, bedeutet dies nicht notwendigerweise, dass die Daten tatsächlich verschlüsselt sind. Sofern Sie ein hohes Maß an Sicherheit benötigen, sollten Sie sich an einen Sicherheitsexperten wenden.
Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.
