Sicherheit ist langweilig und hält nur auf, diesen Eindruck haben nicht nur viele Projektverantwortliche, sondern auch zahlreiche Entwickler. Der schöpferische Prozess wird ja behindert, wenn man sich als Softwaredesigner auch noch um solche Randprobleme kümmern muss. Nur - irgendwann kommen die Probleme, und dann muss ein weit fortgeschrittenes Produkt nachträglich sicher gemacht werden.
Das wird dann wirklich langwierig und hat mit Kreativität nur sehr eingeschränkt zu tun. Sich aber von Anfang an Gedanken zur Sicherheit zu machen, kann hingegen wirklich sehr spannend sein. Gerade wenn es um potenzielle Lücken geht, ist nämlich Phantasie gefragt: Wo überall könnte denn ein ebenso kreativer Angreifer ansetzen?
Dabei geht es weniger um Richtlinien und Konventionen, wichtig sind vielmehr etwas Grundwissen zu typischen Sicherheitslücken und außerdem viel Phantasie, um die Lücken zu vermeiden, die im eigenen Projekt auftreten könnten.
Wir picken uns deshalb einige sehr typische Beispiele heraus, aber nicht einfach als Anleitung zum richtigen Programmieren. Ein Blick hinter die Kulissen ist viel interessanter: Warum ist es so gefährlich, wenn ein Buffer Overflow auftritt? Das Programm stürzt halt ab, das kennt man ja. Was ist daran schlimm? Oder: Externe Programme kann man sehr schön mit system() starten, was gefällt den Security-Leuten denn daran nicht? Und wo liegen sonst noch versteckte Fallen?
Sicherheitskritische Software
Bevor wir in die Details einsteigen, stellt sich die Frage, bei welchen Programmen man überhaupt auf Sicherheit achten muss. Die einfache Antwort ist: bei jedem Programm, wenn auch nicht immer im gleichen Umfang. Eine Sicherheitslücke bedeutet vereinfacht gesagt, dass ein Benutzer mehr kann als er darf - etwa Dateien oder Teile von Dateien lesen, für die er nach den vergebenen Zugriffsrechten keine Leseberechtigung hat, oder unter einer anderen User-ID arbeiten. Beliebtes Ziel ist dabei natürlich der Root-Account.
Um diese zusätzlichen Fähigkeiten zu erlangen, kommen - neben übersehenen Fehlern in der Konfiguration - vor allem Programme in Frage, die genau diese Rechte besitzen, sie aber eigentlich nicht an jeden weitergeben. Das können s-Bit-Programme sein, Daemons, CGI-Skripte oder einfach nur Programme, die ein anderer Benutzer gestartet hat.
Solange sich in diesen Programmen nicht sowieso ein trojanisches Pferd befindet (diesen Fall wollen wir im Augenblick noch ausschließen), muss ein Angreifer das Programm in irgendeiner Form beeinflussen. Bei s-Bit-Programmen könnte er mit ungewöhnlichen Parametern spielen oder die Environment-Variablen anders setzen, als der Programmierer es erwartet. Bei Serverprogrammen sind die Eingaben des Clients der typische Weg für einen Angriff.
CGI-Skripte sind im Grunde ebenfalls Server, die vom Webserver gestartet werden und ihre Parameter vom Browser erhalten. Beispielsweise über temporäre Dateien in /tmp können aber sogar sehr gewöhnliche Programme angegriffen werden, die ein anderer User gestartet hat. Die möglichen Wege sind recht vielfältig, sogar Signale können unerwünschte Folgen haben. In jedem Fall führen unerwartete Eingaben zu ungewollten Ergebnissen, zumindest aus der Sicht des betroffenen Programmierers.
Lernen am schlechten Beispiel
Nehmen wir ein kleines Beispiel: Wir könnten zwar beliebige reale Lücken nehmen, der Einfachheit halber (und um nicht ungerecht zu werden) soll es ein kleines selbst geschriebenes s-Bit-Programm sein. Das Beispiel ist etwas weltfremd, so dass hoffentlich niemand auf die Idee kommt, das Programm wirklich einzusetzen: Mehrere Benutzer tragen ihre Änderungen in eine CHANGES-Datei ein, dürfen aber keine alten Einträge ändern oder gar löschen. Bei den üblichen Unix-Zugriffsrechten gibt es aber kein Append-only. Wir sorgen also dafür, dass die Benutzer in die Datei nicht direkt schreiben können, sondern nur unser s-Bit-Programm.
Zudem stellt das Programm sicher, dass jeder Eintrag mit der korrekten User-Kennung sowie mit Datum und Uhrzeit versehen ist. Weil der Admin die Datei auch nicht ständig überprüfen will, schickt ihm das Programm nach jedem Eintrag eine kurze Mail.
Unser Versuch ist als Listing abgedruckt. Der erste Fehler wird bereits beim Öffnen der Datei gemacht: Sie ist ohne Pfad angegeben.
Listing
|
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define BUFLEN 1024
void addChanges(FILE *f)
{
char buffer[BUFLEN];
time_t t;
printf("Your changes: ");
gets(buffer);
time(&t);
fprintf(f, "%s: %st%snn",
getenv("USER"),
asctime(localtime(&t)),
buffer);
}
int main()
{
FILE *ch;
if(ch=fopen("CHANGES", "a"))
{
addChanges(ch);
fclose(ch);
system("echo CHANGES | mail admin");
return 0;
}
fprintf(stderr,
"Could not open CHANGESn");
return 1;
}
|