Wenige Zeichen zu wenig – und schon ist es passiert. Die eigene Website wurde gehackt. Dafür gibt es zahlreiche Gründe, denn das Einbrechen in fremde Websites ist nicht immer besonders schwer.
Noch heute finden sich Tausende von Internetseiten mit gefährlichen Sicherheitslücken über einfache Suchabfragen mit Google.
Niemand kann dir garantieren, Hacker-Angriffe vollständig zu verhindern, es gilt die Devise: Es programmieren Menschen und Menschen machen Fehler. Genau diese Fehler können Hacker aufspüren und sich, sollten sie böse Absichten haben, zunutze machen. Das Ergebnis: der Server wird in ein Bot-Netz eingespannt, der Quell-Code ausgelesen und/oder manipuliert, Nutzerdaten werden gestohlen.
In diesem Artikel werden wir gemeinsam einige Grund-Maßnahmen durchgehen. Wenn du diese beachtest, kannst du die Gefahr einem Hacker-Angriff zum Opfer zu fallen schon etwas eindämmen.
Hier sind 10 Dinge die du nicht tun solltest, wenn du keinen Hacker auf deiner Website haben willst.
1. Dem Nutzer trauen
Die goldene Regel lautet erst einmal dem Nutzer niemals zu trauen, wirklich nie. Genau genommen, könnte diese Regel alle anderen ersetzen, zumindest aber beinhaltet sie noch einige wichtige Tipps.
Denn du darfst nicht vergessen, was der Nutzer/Client alles tun kann. JavaScript läuft auf dem Clienten, alle Eingaben, die mittels JavaScript überprüft wurden sind, müssen nochmal auf der Server-Seite überprüft werden (siehe Abschnitt 6).
GET- und POST-Werte können vom Nutzer beliebig übergeben werden, alle möglichen Sonderzeichen und sogar ASCII-Codes sind möglich (siehe Abschnitt 8).
Als ich selber angefangen habe, mich mit Webentwicklung zu beschäftigen habe ich einen fatalen Fehler begangen. Ich habe nicht daran gedacht, der Nutzer auch Cookies beliebig verändern kann. Bei einem kleinen Browserspiel wurde die NutzerID im Cookie gespeichert, das Spiel nahm dann ohne weitere Prüfung an, dass es sich um den Nutzer handele.
Ein findiger Nutzer sah das Ganze und hat anschließend selbst die ID für den Administrator gesetzt. Prompt hatte er vollen Zugriff auf alle Verwaltungsfunktionen, hat mich darüber aber informiert und nichts weiter damit angestellt.
Das war eine recht hilfreiche Lektion, die ich hiermit auch an dich weitergebe. Dem Nutzer nicht zu trauen ist das Eine, andererseits musst du auch wissen, was der Nutzer alles verändern kann. Denke dabei auch an eventuell zu verarbeitende Header-Informationen.
Generell gilt: Alle Informationen, die von Client – egal wie – kommen sind „böse“ und müssen je nach Anwendungsfall mit einer White- oder Blacklist auf unerwünschte Zeichen geprüft werden.
2. Keine prepared-Statements verwenden
Ein Klassiker unter den Sicherheitslücken ist die gute, alte MySQL Injection. Es geht darum, dass ungeprüfte Nutzereingaben an die Datenbank weitergegeben werden.
Aus einem
SELECT * FROM benutzer WHERE name = '$name'
kann dann mit einem entsprechenden Inhalt folgendes werden:
SELECT * FROM benutzer WHERE name = '' OR admin = 1 -- '
Fett markiert ist dabei der Inhalt der Variablen. Mittels UNION SELECT können dabei unter Umständen alle Informationen nacheinander aus der Datenbank extrahiert werden.
Dieses SQL Injection Cheat Sheet zeigt dir noch einmal alle Möglichkeiten auf. Wenn man bedenkt, dass teils auch hochsensible Nutzer- und Kontodaten in solchen Datenbanken gespeichert werden, ist eine Absicherung essentiell.
Mittels Prepared Statements wird der Datenbank bereits gesagt, an welcher Stelle Nutzer-Eingaben folgen werden. Dadurch ignoriert sie eventuelle Befehlszeichen innerhalb dieses Bereichs.
Konsequent eingesetzte Prepared Statements sind daher der beste Weg um einer MySQL-Injection vorzubeugen. Die schlechte Nachricht ist jedoch: Es reicht einen Fehler an einer Stelle zu machen und Unbefugte können sich trotzdem Zugriff verschaffen.
Besonders interessant wird es für Hacker dann, wenn du mehrere Projekte auf deinem Server laufen hast, die auf die jeweils andere Datenbank zugreifen können. Hast du dort ein hochmodernes und recht sicheres Projekt mit vielen Kunden-Daten, können diese abgegriffen werden, indem der Angreifer ein anderes, schlecht gesichertes Projekt des Servers attackiert.
Einen MySQL-Benutzer mit globalen Zugriffsrechten oder einem Zugriffsrecht auf mehrere Datenbanken einzurichten, ist daher ein nette Einladung an Hacker, sich auch die anderen Datenbanken einmal genauer anzugucken.
3. register_globals verwenden
In so einem Artikel dürfen natürlich die register_globals nicht fehlen. Der Nachteil dieser veralteten Funktion lässt sich vereinfacht so erklären: Alle POST- und GET-Variablen werden aus dem Array losgelöst und in einer eigenen Variable gespeichert.
Aus $_GET[’name‘] wird dann $name mit dem entsprechenden Wert. Das ist dann blöd, wenn zum Beispiel die Variable $admin bestimmt, ob der Nutzer Zugriff auf den Administrationsbereich hat. Ein ?admin=1 und der Nutzer ist Administrator.
Auch wenn das ein wenig vereinfacht dargestellt ist, lässt sich, denke ich, die grundsätzliche Problematik erkennen. Die Variablen-Namen können beliebig ausfallen und sind damit eine Gefahr für den reibungslosen Ablauf des Skripts.
4. Veraltete Software verwenden
HeartBleed oder die Bash-Lücke sind nur zwei Beispiele. Hinzu kommen Sicherheitslücken bei großer Software wie etwa WordPress.
Wer einen eigenen (v)Server betreibt, muss besonders darauf achten, regelmäßig Updates einzuspielen. Aber auch für alle anderen, die auf fertige Software setzen, gilt: Software regelmäßig aktualisieren.
OpenSource bietet zwar den Vorteil, dass mehr Leute Einsicht in den Code haben und Sicherheitslücken so schneller entdeckt werden können, das Gleiche gilt aber auch für Hacker.
Sie könnten auch bei uralten und scheinbar sicheren Versionen von einem CMS noch eine Sicherheitslücke ausfindig machen.
5. Dateinamen durch unkontrollierte Variablen festlegen
Nehmen wir an, über den GET-Parameter page wird festgelegt, welche Seite PHP anzeigen soll. Diese wird mittels include von dem Webserver geladen.
Wir speichern den Inhalt dieses Parameters in $page und haben dieses Mal Pech, unser PHP-Code sieht nämlich so aus:
include "pages/".$page;
Der Nutzer übergibt jetzt aber in $page „../config.php“ und könnte damit, falls vorhanden, eine interessante Konfigurationsdatei auslesen.
Werden diese Daten nicht geprüft, insbesondere auf Zeichen wie „/ \ .“ kann der Angreifer unter Umständen beliebige Dateien auslesen. Natürlich kennt er die Struktur nicht und muss die Datei-Namen erraten, aber mit ein wenig Glück, findet er nicht nur interessanten Source-Code, sondern zum Beispiel noch Zugangsdaten für den FTP- oder MySQL-Server.
Ein entsprechender Zugang vorausgesetzt (z.B. phpMyAdmin für MySQL) kann der Hacker auch hier die Gewalt über die Datenbank übernehmen – und das kann für den Webmaster sehr unangenehm werden.
6. JavaScript zum Schutz einsetzen
Die Rechtsklick-Sperre um das Speichern von Bildern zu verhindern, das Ausblenden von Inhalten für Administratoren, die Beschränkung von Eingaben auf eine gewisse Zeichenanzahl und die Überprüfung von Formularfeldern.
Es ist schön und gut, wenn JavaScript das übernimmt. Das alleine reicht allerdings nicht aus.
Abgesehen davon, dass JavaScript in jedem Browser deaktiviert werden kann, wird es auf dem Browser des Clients ausgeführt, er selbst kann also das Skript manipulieren und so beliebige Inhalte an den Server senden.
Daher muss der Server in jedem Fall selbst die Eingaben überprüfen und darf sich nicht auf eventuelle Vorprüfungen verlassen.
7. Den Upload jeglicher Dateien erlauben
Ein kleines Foto-Album mit Upload-Funktion für jedermann. Klingt doch erstmal gut, oder? Wir speichern die Dateien unter example.com/dateien/album/.
Blöd nur, wenn wir nicht die Datei-Typen überprüfen. Dann kann ein Hacker ganz einfach eine PHP-Datei hochladen. Da er den Speicherpfad kennt und den Namen einsehen kann, ruft er danach einfach: example.com/dateien/album/dateiname.php auf. Der PHP-Code wird ausgeführt und er kann mit beliebigen Befehlen den Server lahmlegen, Daten stehlen oder gar die komplette Kontrolle übernehmen.
Merke: Hochgeladene Dateien immer auf den korrekten Datei-Typ und die Endung überprüfen. Außerdem sollten die Speicherpfade, etwa über ein PHP-Skript, was die jeweilige Datei von einem geheimen Ort lädt, so gut es geht verschleiert werden.
8. Nutzer-Eingaben ungefiltert ausgeben (XSS)
Schon in Abschnitt 6 ist JavaScript nicht gut weggekommen, und jetzt kommt auch noch das Cross-Site-Scripting (XSS) dazu. Ein beliebtes Anwendungsbeispiel ist eine Suchfunktion, die im GET-Parameter q den Suchstring erwartet.
Wird der Suchstring, der vom Nutzer übergeben wurde, nun ungeprüft ausgegeben, kann der Hacker auch JavaScript-Code einschleußen. Möglich sind von einer weißen Seite über eine Weiterleitung bis hin zu einem Login-Fomular, das die Daten im Hintergrund an eine andere Seite verschickt, viele tolle Sachen 🙂
Da dieses Problem bei wirklich jeder Ausgabe eines Nutzers auftreten kann, ist XSS besonders populär. Viele Sicherheitslücken sind Cross-Site-Scripting-Lücken.
Problematisch wird es natürlich erst dann, wenn ein fremder Nutzer beispielsweise eine entsprechend präparierte URL aufruft, die er etwa per E-Mail geschickt bekommen hat. Der wird es ganz sicher nicht witzig finden, wenn seine Login-Daten plötzlich auch jemand anderem bekannt sind.
Besonders brisant sind solche Lücken dann, wenn es um sensible Daten geht, etwa bei der Website einer Bank.
9. Dem eigenen Skript möglichst viele Recht einräumen.
Gib deinem Skript immer nur die Rechte, die es wirklich braucht. Das betrifft nicht nur die MySQL-Benutzer, sondern eben auch PHP.
Dort gibt es einige interessante Funktionen wie etwa eval() oder system(). Nur wenn du diese wirklich benötigst, solltest du sie aktivieren, andernfalls ist es am besten, diese Funktion über die PHP-Konfiguration komplett zu sperren.
Auch der Benutzer, der die PHP-Skripte ausführt, sollte auf dem Webserver nur so viele Rechte wie nötig haben. Je mehr du dein Skript einschränken kannst, ohne dass die Funktionalität darunter leidet, desto besser.
10. Mit Infos um sich werfen
Je mehr Infos der Angreifer hat, desto leichter fällt es ihm, Sicherheitslücken ausfindig zu machen.
Da wären zum einen die Versionsnummer. Sei es die Version von WordPress, einem anderen CMS oder PHP. Entweder im Quelltext oder im Header finden sich häufig entsprechende Versionsnummern. So kann der Hacker gezielt recherchieren, welche Sicherheitslücken für diese Version funktionieren.
Das erleichtert Angriffe auf Websites erheblich. Eben so wie Fehlermeldungen. Sie können unter Umständen verraten, wie ein Skript funktioniert und auch Sicherheitslücken erkennbar machen, etwa wenn MySQL ein unerwartetes Zeichen bekommt und dieses nicht verarbeiten kann – häufig ein Zeichen dafür, dass eine MySQL Injection möglich ist.
Fehlermeldungen sind wichtig, aber nur im Entwicklungsmodus. Ist die Website für alle erreichbar, sollten diese ausgeschaltet werden.
Daten gibt es auch auf den eigenen Geräten. Ein Virus, der gezielt nach FTP-Daten sucht oder ein unachtsames Posten von eigenem Quelltext, um Hilfe bei einem Problem zu bekommen, reichen aus, um wichtige Daten abzugreifen. Ist ein wichtiges Passwort erst einmal jemand anderem bekannt, kann es sehr mühselig werden, wieder vollen Zugriff über den Server zu erlangen. Auch hier spreche ich aus eigener Erfahrung.
Fazit zu den Server-Sicherheitstipps
Gerade komplexe, dynamische Websites bieten eine große Angriffsfläche. Wenn dann noch unerfahrene Webmaster damit hantieren, besteht die Gefahr, dass man die Kontrolle über die eigenen Daten oder den eigenen Server verliert.
Eine hunderprozentige Sicherheit gibt es nie, aber mit diesen 10 Tipps für mehr Sicherheit gegen Hacker-Angriffe durch XSS, MySQL Injections & Co. kannst die Wahrscheinlichkeit erhöhen, nicht das Opfer eines solchen Angriffs zu werden,
Ein Gedanke zu „10 Dinge die du nicht tun solltest, um es Hackern leicht zu machen“