vom 31.12.2011
Hacker-Gefahr: Wie vermeidet man die größten Sicherheitsrisiken, wie SQL Injection oder Cross-Site-Scripting (XSS) bei der Entwicklung von Webseiten mit PHP?
Manch Programmierer und noch mehr sehr viele User nehmen das Thema Sicherheit nicht unbedingt so bierernst.
Im Falle von Programmierern mag es vielleicht daran liegen, dass sie sich der möglichen Gefahren noch nicht bewusst geworden sind. Gerade wenn man anfängt, Webseiten mit PHP zu bauen, freut man sich oft mehr darüber, dass es überhaupt funktioniert und vergeudet wenig Zeit damit, sich zu informieren. Ich gebe zu, dass mir das lange Zeit auch so erging. Allerdings hatte ich in dieser Zeit auch keine Webseiten online oder für andere erstellt, sondern war eher mit Lernen beschäftigt. Spätestens wenn man aber die Verantwortung für eine Kundenwebseite hat oder eine Webseite betreibt, auf welcher sich User registrieren können, übernimmt man auch die Verantwortung für andere.
User wiederum sind sich der Problematik oft erst recht nicht bewusst, da sie schon die technischen Möglichkeiten gar nicht kennen.
In manchen Fällen reicht es für einen großen, wirtschaftlichen Schaden schon aus, wenn ein Hacker lediglich an den Usernamen, die E-Mail-Adresse und das mit MD5 verschlüsselte Passwort (selbstverständlich sollten Passwörter nur verschlüsselt in der Datenbank gespeichert werden) eines Users in Freizeitforum Sowieso herankommt.
Wenn der unvorsichtige User nämlich dieselbe Email-Adresse und dasselbe Passwort z.B. bei Amazon verwendet, hat der Hacker Spaß. Auch verschlüsselte Passwörter sind mit Hilfe von Brute-Force leicht zu knacken. Harmlosere Varianten sind das Versenden von Spam-Mails über die (vermeintlich) Mailadressen der User oder das Posten von Porno-Links unter dem Account des Users in Freizeitforum Sowieso. Oder auch das "Entführen" von Facebook-Profilen, wenn dort ebenfalls dieselbe Mail-Adresse und Passwort verwendet wurden.
Hackerangriffe auf Webseiten basieren meist auf SQL-Injections oder Cross-Site-Scripting (XSS). Ich werde beide Varianten kurz erklären und ebenso, was man bei der Programmierung beachten sollte, um so etwas zu vermeiden.
Kritisch bezüglich SQL-Injections und Cross-Site-Scripting sind Werte/Parameter, welche von außen manipulierbar sind und dann vom Server verarbeitet werden und/oder auf der Webseite wieder ausgegeben werden.
Diese Werte können durch Manipulation der URL (GET-Parameter), durch das Senden von Formulardaten (GET- oder POST-Parameter) oder auch über das Manipulieren von Werten in Cookies Einfluss nehmen. Besondere Beachtung bei der Verarbeitung finden müssen also immer:
$_GET["Parameter"]$_POST["Parameter"]$_COOKIE["Parameter"]Generiert man dynamische Webseiten mit PHP, greift man in der Regel auch auf eine MySQL-Datenbank zurück, liest dort Daten aus, trägt sie ein, ändert sie und löscht sie mit Hilfe von PHP-Scripten.
SQL-Injections schleusen quasi ungewollte Strings in diese PHP-Scripte ein und manipulieren damit die Datenbank oder lesen kritische Daten aus.
Z.B. möglich ist das bei einer SELECT-Abfrage, welche auf Daten aus einem Formular oder ein URL zurückgreift:
Gibt der User nun ganz normal seinen Benutzernamen in das Formular ein, dessen gesendete Daten mit diesem SELECT-Statement verarbeitet werden, lautet die Ausgabe
SELECT * FROM users WHERE name='Max';
Angenommen, der User gibt nun folgenden String in das Formular ein: '; DELETE * FROM users WHERE '1 , so lautet die Ausgabe:
SELECT * FROM users WHERE name=''; DELETE * FROM users WHERE '1';
Es würde also über das Formularfeld für den Benutzernamen eine Löschabfrage eingeschleust, welche alle User löscht.
Um eine SQL-Injection zu verhindern, sollte man die gesendeten Daten (GET, POST, COOKIE), die in einer SQL-Abgfrage verwendet werden, maskieren.
Für MySQL und PHP eignet sich dafür am besten die Funktion mysql_real_escape_string().
Die Beispiel-SQL-Abfrage sollte also wie folgt lauten:
Hinweis:
In älteren PHP-Versionen gab es eine Funktion "Magic Quotes". Wenn magic_quotes_gpc in der php.ini auf "on" gesetzt ist, funktioniert mysql_real_escape_string() nicht mehr so, wie sie soll, da der String dann quasi doppelt maskiert wird.
Diese Funktion sollte also auf "off" gesetzt werden. Das geht direkt in der php.ini, wenn man darauf Zugriff hat, über eine PHP-Funktion während der Laufzeit und über die .htaccess, was die von mir bevorzugte Variante ist und was ich grundsätzlich vorsichtshalber bei jeder Webseite mache:
php_flag magic_quotes_gpc Off
Cross-Site-Scripting erfolgt über dieselben Wege, wie eine SQL-Injection. Es wird jedoch HTML eingeschleust und funktioniert über die Interpretation des Browsers. Am häufigsten werden in die Formularfelder JavaScripts oder iFrames, welche ihrerseite Scripte laden, geschrieben.
Der sicherste Weg, Cross-Site-Scripting zu vermeiden, ist HTML für User nicht zu erlauben. D.h. Werte, die direkt auf der Webseite erscheinen oder in die Datenbank geschrieben und wieder ausgegeben werden, sollten nicht als HTML vom Browser interpretiert werden.
Hierzu verwende ich die PHP-Funktion html_entities(), welche alle HTML-Zeichen escaped.
Beispiel:
Jemand gibt in ein Formularfeld folgendes ein:
Gebe ich diesen String mit PHP einfach so, wie er ist aus
wird der Browser Folgendes anzeigen:
Ein dicker Text
Das HTML wird also interpretiert, es wird der Text fettgedruckt dargestellt.
Escape ich den String mit htmlentities()
wird der String umgewandelt in: <strong>Ein dicker Text</strong> und die Ausgabe im Browser lautet: <strong>Ein dicker Text</strong>. HTML wird nicht interpretiert.
Besteht dennoch die Notwendigkeit, es dem User zu ermöglichen, seine Eingaben zu formatieren, Bilder, Smilies und dergleichen einzufügen, sollte man zum Einen so etwas, wie BBCode verwenden, zum Anderen auch genau festlegen, was erlaubt ist und sich dabei auf harmlose HTML-Elemente beschränken, welche keinen Schaden anrichten können.
Beim Benutzen der PHP-Funktion $_SERVER["PHP_SELF"] im action-Attribut eines Formulars können ebenfalls Skripte auf der Webseite eingeschleust werden. Indem man in die URL in der Adresszeile den Code eingibt, kann man über das Absenden des Formulars das Ausführen dieses Codes bewirken.
Deshalt sollte auch diese Funktion immer mit htmlentities() escaped werden.
Die meisten Admin-Bereiche haben natürlich einen eigenen Login, der je nach Programmierung mehr oder weniger schützt. Schafft es ein Hacker jedoch, sich in diesen Admin-Bereich einzuloggen, indem er irgendwie an das Admin-Passwort herankommt, stehen ihm weitreichende Möglichkeiten offen.
Darum ist es besser, den Admin-Bereich noch zusätzlich über den servereigenen Verzeichnisschutz abzusichern. Man muss sich dann halt leider doppelt einloggen, erreicht aber eine größere Sicherheit.
Haben User die Möglichkeit, Dateien hochzuladen, sollten diese Dateien immer auf ihre Endung bzw. ihre Datei-Art überprüft werden und nur solche zugelassen werden, die auch nötig sind. Bei Galerien z.B. nur JPEGs, GIFs und PNGs.
Werden sensible Daten, wie Passwörter oder sogar Kreditkartendaten, aber auch Adressdaten gesendet (auch vom Browser an den Server und zurück oder per E-Mail), sollte das Versenden immer verschlüsselt erfolgen.
Eigenentwicklungen haben den Vorteil, dass Außenstehende nicht oder nur sehr schwer an die Struktur (die PHP-Skripte, die Tabellennamen in der Datenbank) herankommen. Nachteilig ist, dass sie eben häufig von nur einem oder sehr wenigen Entwicklern erstellt, getestet und geprüft werden und damit fehleranfälliger sind.
Bekannte Foren- und Shopsysteme sowie Content Management Systeme haben folglich den Nachteil, dass auch Hacker an die Core-Dateien und Datenbankstrukturen gelangen und diese auf Schwachstellen untersuchen können, Werte und Parameter kennen u.s.w. Da diese Systeme aber häufig von vielen Leuten entwickelt und über Jahre von Entwicklern aber auch Anwendern getestet sind und werden, werden Sicherheitslücken schneller aufgedeckt und gefixt. Hier sollte man auf regelmäßige Updates achten und die Software immer auf dem neuesten Stand halten.
Unbekannte, neuere Systeme halte ich für am kritischsten. Hier besteht oft ein Ähnliches Problem, wie bei der Eigenentwicklung (wenige Entwickler, wenige Tester), jedoch kommen Hacker gut an das Core-System heran, wenn es frei downloadbar ist oder verkauft wird und können es somit untersuchen.
Dieser Artikel erhebt keinen Anspruch auf Vollständigkeit. Es gibt sicher noch weitere Möglichkeiten für Hackerangriffe und auch Schutzmaßnahmen. Ich habe versucht, ein paar Wichtige und häufig Vorkommende zu erläutern und Möglichkeiten darzustellen, mit diesen Gefahren umzugehen.