Einiges zum Thema CGI-Sicherheit
Inhalt:
Ok, nachdem es im Forum tagelang nur im Kreis ging, fange ich einfach mal an...
Dieser Wiki-Artikel wird einiges zum Thema "Wie mache ich meine CGI-Skripte sicherer?"
beinhalten. Da das aber ein sehr breit gefächertes Thema ist, ist es unmöglich alles
aufzuschreiben. Aber jeder ist dazu eingeladen, Tipps hier einzupflegen...
--
ReneeBaecker
Ein guter Lesehinweis ist auch
perldoc perlsec ...
Benutzereingaben
Es gibt einen Grundsatz, den man immer berücksichtigen sollte:
Traue keiner Benutzereingabe!
Als Programmierer sollte man immer denken "Der User will mir schaden". Man sollte also eine gesunde Paranoia entwickeln...
CGI.pm
Als allererstes sollte man das Modul CGI.pm verwenden. Es nimmt einem viel Arbeit ab und
reduziert so die Fehlerwahrscheinlichkeit. Das Modul wird schon seit einigen Jahren entwickelt und
hat somit einen sehr guten Stand.
Taint-Modus
Man sollte das Skript immer im Taint-Modus laufen lassen. Dazu wird
perl beim Aufruf die Option
-T mitgegeben. Unter UNIX/Linux geht das einfach in der Shebangzeile am Anfang des Skriptes:
#!/usr/bin/perl -T
...
In diesem Modus sorgt Perl dafür, dass Eingaben, die aus der "bösen Außenwelt" kommen, automatisch als "tainted" (befleckt) markiert werden und in kritischen Funktionsaufrufen nicht verwendet werden können. Das Tainting funktioniert allerdings nicht automatisch bei der Verwendung von XS/C-Modulen, hier ist Vorsicht geboten.
Leider gibt es hier einen Unterschied zwischen Linux und Windows. Bei Windows bringt es nichts, wenn das
-T im Shebang steht, weil die Shebangzeile nicht vor dem Aufruf des Interpreters ausgewertet wird. Die Option muss schon beim Starten des Interpreters bekannt sein. Irgendwo in der Webserverkonfiguration (je nach Webserver) muß man festlegen, wie dieser mit der Endung
.pl (o.ä.) umgehen soll. Dort schreibt man dann nicht
C:\perl\bin\perl.exe ..., sondern eben
C:\perl\bin\perl.exe -T .... Blöd daran ist nur, daß die Einstellung dann für alles, bzw. wenn möglich, für den so konfigurierten Teil gilt. Aber weil man
-T bekanntlich sowieso immer anwenden soll, ist es auch wieder kein Problem.
HTML und BBCode
Injizierter HTML- und Javascript-Code kann zu Angriffen auf die Client-Seite einer Anwendung verwendet werden. Wenn man gewisse HTML-Elemente zulassen will (z.B. in einem Forum), ist es geschickt, eines der BBCode-Module von CPAN zu benutzen. So kann man alle HTML-Elemente, die der Benutzer direkt eingibt, "unschädlich" machen, z.B. mit HTML::Entities.
HTML-Escaping
Die Template-Module HTML::Template und HTML::Template::Compiled bieten auch die Möglichkeit, ein "default_escape" zu setzen. Ist das der Standard-Wert auf 'html' eingestellt, werden automatisch bei allen Parametern die Sonderzeichen umgewandelt in Entities. Das vereinfacht das Verhindern von XSS.
Datenbanken
Das DBI-Modul bietet die wunderbare Möglichkeit, die ?-Notation (
Platzhalter) zu verwenden. Damit werden automatisch alle Sonderzeichen gequotet und die Möglichkeit des Injizierens von SQL-Code verhindert. Siehe auch "Placeholders and Bind Values" in
perldoc DBI. Weiterhin gibt es eine (experimentelle) Möglichkeit, Ein- und Ausgabewerte als "tainted" zu markieren (Optionen
TaintIn?,
TaintOut?, Taint). Zu diesen Optionen ist zu sagen, dass sich
TaintIn? z.b. auch bei Platzhaltern beschwert, bei denen
eigentlich nichts passiert. Benutzt man diese Optionen, muss man also zusätzlich zu den Platzhaltern jede Variable untainten.
Öffnen einer Datei
Grundsätzlich sollte man nicht den User bestimmen lassen, wie der Dateiname lautet. Man sollte eigentlich immer selbst festlegen, wie die Datei heißt und wo sie hingespeichert wird.
Außerdem ist die Drei-Parameter-Form von open() (also
open (FILEHANDLE, ">", $dateiname)) sicherer, da das Umlenkungszeichen damit eindeutig festgelegt wird. Beim Verwenden des Taint-Modus wird man automatisch vor der Verwendung von unsicheren Dateinamen geschützt.
Öffnen einer Pipe
Wenn z.B. mit sendmail eine E-Mail verschicken werden soll, wird gerne der typische Fehler gemacht, die E-Mail-Adresse
des Empfängers direkt in die Kommandozeile zu schreiben:
open PIPE, "|/usr/lib/sendmail $empfaenger";
Was fällt auf? Genau, $empfaenger ist hier vermutlich eine Benutzereingabe. Der sollten wir niemals trauen. In die
Kommandozeile gehören nur selbst festgelegte Parameter. Den Empfänger kann man auch mit der Option -t und einer "To:"-Zeile bestimmen.
# Etwas besser, aber noch nicht gut:
open PIPE, "|/usr/lib/sendmail -t" or die $!;
print PIPE <<EOM;
To: $empfaenger
Subject: Blubber
Hallo $name,
usw.
EOM
...
Aber auch das ist nicht sicher.
Denn erstens kann $empfaenger oder $name mehrere Zeilen beinhalten, die noch ein paar zusätzliche
Header-Zeilen wie z.B. "Bcc:
boeser_bube@domain.example" beinhalten kann oder auch eine komplette
E-Mail hinzufügen kann. sendmail betrachtet eine E-Mail als fertig, wenn im Body der Punkt alleine
auf einer Zeile vorkommt.
Also, Usereingaben gehören auch nicht ungeprüft in den Header einer E-Mail, und sendmail startet man
mit der Option "-oi", die das mit dem erwähnten Punkt verhindert.
# Prüfe $empfaenger auf Gültigkeit, z.B. mit Email::Valid
# Ersetze stumpf alle unerwünschten Zeichen:
$empfaenger =~ tr/\r\n\t\f\0//d;
open PIPE, '|-', '/usr/lib/sendmail -t -oi' or die $!;
print PIPE <<EOM;
From: test@test.com
To: $empfaenger
Subject: Blubber
Hallo $name,
usw.
EOM
...
Haeufig kann man solche Pipe-Verwendungen vermeiden, indem man z.B. auf Module zurueckgreift. Im Fall von "Mails versenden" kann man z.B. das Mail::Sender-Modul benutzen.
Verwendung von eval
Man sollte im Allgemeinen auf String-evals mit Daten aus unsicheren Quellen verzichten, da der String eine "böse" Zeichenfolge beinhalten könnte. Auch hier wird man im Taint-Modus geschützt.
Wenn doch ein String-eval mit unbekannten Inhalt verwendet werden soll, kann man auf das Module Safe zurückgreifen, mit dem man bestimmte Perl-Funktionen (Opcodes) erlauben oder ausschalten kann. Es ist allerdings möglich, dass Safe Sicherheitslücken hat!
Neueste Perl-Version
Auch das Perl-Binary kann typische, aus der C-Welt bekannte Fehler wie Buffer Overflows enthalten. Deshalb sollte man möglichst die neueste Perl-Version verwenden. Bei kritischen Bugfixes werden auch die älteren Stränge (5.6.x, 5.003_xx) aktualisiert.
Weitere CPAN-Module für CGI-Programmierung
Weiterführende Links
CGI-Sicherheit
Sicherheitsprobleme durch Javascript
Cross Site Scripting (XSS) und Cross-Site Request Forgery (XSRF)
Es gibt noch mehr Links, die ich aber auf Grund der unklaren deutschen Rechtslage hier nicht einfüge. (GwenDragon?)
Ergänzungen, Kommentare
Text ergänzt, Umlaute eingefügt. --
PlTk - 28 Dec 2005
--
HaraldBongartz - 30 Dec 2005
Links hinzugefügt --
GwenDragon - 21 Jul 2008, 23 Jul 2008