7.2Bedrohungen, Angriffe, Sicherheitslücken und Maßnahmen
Bevor wir uns theoretisch und praktisch mit der IT-Sicherheit für App-Programmierer befassen, wollen wir die Begriffe Bedrohung, Maßnahme, Angriff und Sicherheitslücke klären.
Jede App, jedes IT-System oder jede Infrastruktur ist bedroht. Eine Bedrohung gegen eine Online-Banking-App beispielsweise wäre der unbefugte Zugriff auf die in der App hinterlegten Zugangsdaten zum Konto.
Sie als Programmierer können diese Bedrohung nicht beseitigen, denn eine Bedrohung ist immer vorhanden. Sie können aber Maßnahmen treffen, um die Bedrohung zu minimieren. In diesem Fall wäre eine denkbare Maßnahme die Verwendung einer angemessen sicheren Verschlüsselung, um die Zugangsdaten zu schützen.
Ein Angreifer, der in den Besitz der Zugangsdaten kommen möchte, kann auf verschiedene Arten versuchen, die Zugangsdaten zu erlangen. Diese Arten nennt man Angriffe. Wirksame Maßnahmen hindern einen Angreifer daran, erfolgreiche Angriffe durchzuführen. Weist ein Programm eine Sicherheitslücke auf, so kann ein Angreifer mit Hilfe eines Angriffs eine Bedrohung realisieren. Eine mögliche Sicherheitslücke wäre im vorliegenden Beispiel die falsche Verwendung von Kryptografie, so dass der Angreifer die verschlüsselten Zugangsdaten entschlüsseln kann.
Als Programmierer müssen Sie sich darüber im Klaren sein, wodurch die eigene App bedroht wird. Denn eine naheliegende Regel ist: Es sind nur Maßnahmen gegen existente Bedrohungen notwendig. Eine App, die keine Daten speichert, muss auch keine Maßnahmen gegen potenziellen Datendiebstahl treffen. Nun ist dieses Beispiel etwas übertrieben und geht an der eigentlichen Problemstellung vorbei: Wie kann ich herausfinden, welche Bedrohungen denn überhaupt auf meine App wirken?
Als Programmierer müssen oder sollten Sie kein Fachmann für IT-Sicherheit sein. Sie haben genug damit zu tun, die Programmiersprache, die API und die Plattform zu kennen, für die Sie programmieren. Der Projektplan lässt in der Regel noch nicht einmal genug Zeit, um alle funktionalen Anforderungen ausreichend zu implementieren. Woher soll dann noch die Zeit kommen, die nichtfunktionalen Anforderungen an IT-Sicherheit zu berücksichtigen?
Bedrohung, Angriff und Maßnahmen lassen sich übersichtlich in sogenannten Bedrohungsbäumen darstellen. Für das vorstehende Beispiel, den unbefugten Zugriff auf Zugangsdaten, sieht ein möglicher Bedrohungsbaum so wie in Abbildung 7.1 gezeigt aus.
Es gehört einiges an Fleißarbeit und Erfahrung mit Sicherheitslücken und Angriffen dazu, um alle erdenklichen Bedrohungen für eine App zu identifizieren und diese Bedrohungen samt möglicher Angriffe und Maßnahmen in Bedrohungsbäumen darzustellen. Allerdings ist die Kenntnis möglicher Bedrohungen die Grundlage angemessener und effizienter Maßnahmen – ganz getreu der Erkenntnis, die der bekannte chinesische Stratege und Heerführer Sun Tzu schon vor 2500 Jahren notierte:
Wenn du den Feind und dich selbst kennst, brauchst du den Ausgang von hundert Schlachten nicht zu fürchten. Wenn du weder den Feind noch dich selbst kennst, wirst du in jeder Schlacht unterliegen. (Sun Tzu, Die Kunst des Krieges)
7.2.1Arten von Sicherheitslücken
Eine Sicherheitslücke ist ein Fehler, den ein Angreifer ausnutzen kann, um schädliche Aktionen auszuführen. Fehler können sich über verschiedene Wege in eine App einschleichen. Man unterscheidet zwischen Design- und Implementierungsfehlern.
Designfehler sind Fehler, die ihren Ursprung in der Architektur oder Anwendungslogik haben. Ein klassischer Designfehler ist z. B. der Verzicht auf die Verschlüsselung für die Übertragung sensibler Daten oder die clientseitige Validierung von Sicherheitsparametern. Designfehler sind schwer zu finden und schwer zu beheben, insbesondere sobald eine App einmal implementiert ist.
Neben Designfehlern gibt es das große Feld der Implementierungsfehler. Darunter fallen alle Fehler, die in der Implementierungsphase einer App auftreten, also bei der Programmierung. Sie reichen von der Verwendung unsicherer Funktionen über das Auftreten sprachspezifischer Sicherheitslücken (z. B. Formatstring- und Speicherfehler in C-Funktionen), die falsche oder fehlende Verwendung von Sicherheitsfunktionen bis hin zu arithmetischen Fehlern und Überläufen. Implementierungsfehler lassen sich mitunter einfacher finden als Designfehler, einige sogar durch die automatisierte Analyse des Quellcodes.
Das Kreuz mit dem C
Eine grundsätzliche Gefahr bei der Arbeit mit Objective-C ist die düstere Vergangenheit dieser Sprache. Objective-C ist ein Nachfahre der Sprache C, und C weist einige konzeptionelle Sicherheitslücken auf, die man durch die Verwendung von C in ein iOS-Projekt einschleppen kann. Die bekannteste dieser Sicherheitslücken ist der Buffer Overflow. Da wir ihn oft und ausführlich genug beschrieben haben, erwähnen wir ihn hier nur kurz, um Ihr Bewusstsein für die Gefahren von C zu schärfen.
C prüft keine Grenzen. Das bedeutet, dass der Programmierer bei der Angabe von Grenzen in Funktionen durch Unachtsamkeit Grenzen und damit Speicher überschreiben kann. Ein Beispiel dafür ist die Funktion strcpy zum Kopieren von Zeichenketten in die Standard-C-Library. strcpy übernimmt zwei Parameter, char *s1 und const char *s2, und kopiert s2 inklusive abschließender Null (\0) nach s1.
#include <stdio.h>
void cpStr(char* in)
{
char tmp[8];
strcpy(tmp, in);
printf("%s\n", tmp);
}
int main(int argc, char* argv[])
{
cpStr(argv[1]);
return 0;
}
Das Programm nimmt den ersten Kommandozeilenparameter und kopiert ihn in der Funktion cpStr in einen statischen Buffer von acht Zeichen Größe.
Das geht so lange gut, bis der Parameter länger als sieben Zeichen ist (zuzüglich abschließender Null) und somit die Größe des Zielbuffers tmp überschreitet. Dann schreibt C nämlich einfach weiter und überschreibt damit gnadenlos Stack-Speicher: Ein Buffer Overflow findet statt. Schleust dann ein Angreifer statt harmloser Zeichenkombinationen Shellcode als Kommandozeilenparameter ein, kann er über diese Sicherheitslücke diesen Shellcode auf dem System ausführen – ein sicherheitstechnischer GAU.
Das Beispiel zeigt, dass auch die vermeintlich korrekte Verwendung von C-Funktionen zu schweren Sicherheitslücken führen kann. Verwenden Sie daher, wenn Sie sich über die potenziellen Folgen nicht vollkommen im Klaren sind, möglichst immer die höchste Abstraktionsebene – im Regelfall also Cocoa.
C ist eine gute Sprache. Sie setzt aber voraus, dass der Programmierer weiß, was er tut; und in der Regel haben Sie als Programmierer bei der Implementierung einer App Besseres zu tun, als sich um die Feinheiten der C-Programmierung zu kümmern.
Das Vermeiden von Implementierungsfehlern setzt Wissen und Erfahrung beim Programmierer voraus. Der Vermeidung von Designfehlern müssen Sie sich methodisch nähern, indem Sie die Architektur einer App prüfen, bevor sie in die Implementierungsphase kommt. Eine bewährte Methodik dafür ist das Threat Modeling, das wir im folgenden Abschnitt ausführlich beschreiben.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.