Zwölf Gebote für sichere Web-Anwendungen
Artikel erschienen in Swiss IT Magazine 2007/08
Eine wesentliche Grundregel für die Sicherheit jeglicher Applikation lautet, allen Eingaben des Benutzers zu misstrauen. Alles, was vom Benutzer editiert werden kann, ermöglicht das potentielle Einfügen von Schadcode und gilt als unsicher, bis das Gegenteil bewiesen wurde. Eine einfache Möglichkeit, Eingaben zu prüfen, besteht darin, sie nach ungültigen Elementen zu durchsuchen und sie aufgrund der Resultate als ungültig einzustufen.
So könnte eine Webseite, die es dem Benutzer ermöglicht, eigene HTML-Anweisungen einzugeben, die Eingabe auf die Verwendung von JavaScript filtern. So nützlich dies zunächst klingt, so offensichtlich liegt der Nachteil dieses Verfahrens auf der Hand: Sofern der Filter nicht sämtliche Angriffsmethoden in allen denkbaren Varianten erkennt, werden stets Sicherheitslücken existieren.
Daher ist es oft sinnvoll, ent-
gegengesetzt zu arbeiten. Statt gewisse Elemente zu verbieten und den Rest zu erlauben, wird alles mit einigen zulässigen Ausnahmen verboten. So könnte eine Webseite für Benutzereingaben beispielsweise generell alle HTML-Anweisungen ausfiltern, mit Ausnahme derer, die explizit erwünscht sind. Der Aufwand, einen solchen Filter im Bedarfsfall um ein oder mehrere weitere erlaubte Anweisung zu erweitern, ist im Hinblick auf die erreichte Sicherheit zu vernachlässigen.
Doch nicht immer sind diese aufwendigen Prüfungen überhaupt notwendig. Stattdessen reicht es häufig schon aus, gewisse Richtlinien zu beachten, so dass es unmöglich wird, Schadcode einzufügen. Solche Verfahren für vier gängige Angriffsmethoden – Pufferüberläufe, Cross-Site-Scripting, SQL- und XPath-Injection sowie Kanonisierung – werden im Folgenden vorgestellt.
Pufferüberläufe stellen eine sehr weit verbreitete Angriffsmethode dar und basieren auf dem Konzept, dass in zahlreichen Anwendungen davon ausgegangen wird, dass eine Eingabe eine gewisse Länge nicht überschreitet. Falls diese vermutete maximale Länge allerdings doch überschritten wird, so kann es zu nicht vorhersagbaren Resultaten kommen. In der Regel wird Speicher überschrieben, der für andere Aufgaben gedacht ist – eventuell auch Speicher, der ausführbaren Code enthält.
Indem ein Angreifer also bewusst überlange Eingaben erzeugt, kann er unter Umständen eigenen Code in Speicherstellen injizieren, die normalerweise Code der Anwendung enthalten. Um dies zu verhindern, lautet die erste Grundregel:
- Jede Eingabe muss auf ihre maximal gültige Länge geprüft werden.
Bei Cross-Site-Scripting-Angriffen (XSS) werden unsichere und sichere Informationen vermischt, die in der Regel von verschiedenen Webseiten stammen. So könnte einer Webseite über eine Benutzer-
eingabe beispielsweise JavaScript-Code untergeschoben werden, der Daten der Webseitenbesucher an den Angreifer versendet. Dadurch kann dieser beispielsweise die Benutzernamen und Session-IDs der Surfer ermitteln, um schliesslich deren Session zu übernehmen.
Je nachdem, ob der Schadcode auf dem Client oder auf dem Server ausgeführt wird, spricht man von client- oder serverseitigem Cross-Site-Scripting. Der einzige Schutz gegen diese Art von Angriffen ist das weiter oben bereits erwähnte Filtern von Eingaben und die Prüfung anhand erlaubter Elemente. Die zweite Grundregel lautet also:
Eingaben können jedoch nicht nur über Eingabefelder in eine Anwendung gelangen. Statt dessen bieten auch andere Elemente einer Webanwendung Möglichkeiten, Eingaben zu manipulieren. Dazu gehören Abfragezeichenfolgen, Formularfelder, Cookies und HTTP-Header.
Abfragezeichenfolgen werden in der Regel an Webadressen angehängt, um Parameter zu übergeben. Beispielsweise wird in Communities auf der Profilseite zumeist ein solcher Parameter genutzt, um das anzuzeigende Profil zu bestimmen. Solange solche Abfragezeichenfolgen nur Werte annehmen, die im Rahmen der Anwendung zulässig sind, funktioniert alles einwandfrei.
Angreifer können diese Werte aber manipulieren, um bewusst Fehler zu provozieren. Sind Webanwendungen nicht so programmiert, dass sie im Fehlerfall auf einen Standardwert zurückgreifen oder zumindest eine angepasste Fehlerseite anzeigen, läuft man Gefahr, dass eine detaillierte, technische Fehlermeldung ausgegeben wird, die dem Angreifer nähere Informationen über das System liefert. Die fünfte Grundregel lautet also:
Authentifizierung und Autorisierung sind zwei Verfahren, die in der Regel gemeinsam genutzt werden. Während die Authentifizierung dazu dient, einen Benutzer zu erkennen, wird die Autorisierung genutzt, um einem Benutzer Zugriff auf bestimmte Ressourcen zu gewähren.
Die einfachste Variante für einen Angreifer, sich als einen anderen Benutzer auszugeben, liegt darin, den Netzwerkverkehr abzuhören. Werden sensitive Informationen wie beispielsweise Anmeldedaten unverschlüsselt übertragen, kann ein Angreifer bereits auf diese einfache Art an die notwendigen Informationen gelangen, um ein Benutzerkonto zu übernehmen. Um sich gegen einen solchen Angriff zu schützen, lautet die achte Grundregel:
Gelingt es einem Angreifer, sein Benutzerkonto in eine höhere Berechtigungsgruppe wie beispielsweise die Gruppe der Administratoren einzutragen, erhält er Zugriff auf weitere Teile der Anwendung und eventuell auch auf den Server, auf dem die Webanwendung ausgeführt wird.
Da solche Angriffe per se nicht verhindert werden können, kann hier lediglich präventiv Schadensbegrenzung betrieben werden. Dazu sollten sämtliche Benutzer jeweils nur über die Rechte verfügen, die zum Betrieb der Anwendung absolut notwendig sind. Dies gilt dabei nicht nur für die Benutzer der Webanwendung, sondern auch für die Systembenutzer, mit denen beispielsweise der Webserver ausgeführt oder auf die Datenbank zugegriffen wird.
Die elfte Grundregel lautet demnach:
- Jeder Benutzer darf nur über die für seine Aufgabe wirklich notwendigen Berechtigungen verfügen.
Des weiteren können Angreifer versuchen, mit nicht vertrauenswürdigem Code den vertrauenswürdigen Code der Anwendung zu kapern, um über diesen und in dessen Kontext Anweisungen auszuführen. Dies wird als lauernder Angriff bezeichnet. In .NET bietet Code Access Security ein Verfahren, um sich vor solchen Angriffen zu schützen. Um sich generell vor solchen Angriffen zu schützen, gilt deshalb die zwölfte Grundregel:
- Der Zugriff auf vertrauenswürdigen Code ist durch entsprechende Prüfungen abgesichert.
So funktioniert SQL-Injection
So funktionieren Cookie-Replay-Angriffe
Elementar für die Sicherheit von Webanwendungen ist, grundsätzlich sämtlichen Eingaben zu misstrauen und prinzipiell eine Fehlerbehandlung für ungültige Eingaben vorzunehmen. Viele Angriffe sind nur deshalb erfolgreich, weil es dem Angreifer gelingt, einen Fehler zu provozieren, der von der Anwendung nicht abgefangen wird.
Die zwölf Grundregeln in diesem Artikel können daher als Richtlinie dienen, Code an den entsprechenden Stellen auf potentielle Angriffsflächen zu überprüfen. Gleichzeitig muss aber berücksichtigt werden, dass es sich dabei doch bloss um einen ersten Schritt hin zu sicheren Web-Anwendungen handeln kann, dem weitere Massnahmen folgen müssen.