Sönke: Sichere Scripte schreiben.

Gutes Nächtle Euch allen!

Kleine Warnung vorweg. Das hier könnte etwas länger werden. Ich habe zwar gerade einmal nicht so ganz konkret ein Problem, Fragen aber trotzdem. :)

Im Prinzip ist mein Anliegen ganz einfach. Nachdem ich mich so langsam in PHP eingearbeitet habe interessiert mich zur Zeit vor allem was - und worauf - man insgesamt achten sollte, wenn man erreichen will das seine eigenen Scripte nicht das Sprichwörtliche Scheunentor darstellen. Eventuell will man die ja auch einmal auf die Menschheit loslassen. Ganz konkret ist das Thema also welche Sicherheitsrelevanten Aspekte man kennen sollte.

Mir ist klar das mir jetzt hier wohl kaum jemand eine ausführliche Einführung geben wird/will; ist auch gar nicht meine Absicht. Habe mir schon selbst die paar Quellen die ich finden konnte zu Gemüte geführt (Und mir sogar den einen oder anderen eigenen Gedanken gemacht ;o) ). Nur habe ich hier und dort noch ein paar kleine Nachfragen Und natürlich interessiert mich auch alles das was mir bisher noch so entgangen ist.

Mit Eurer Erlaubnis werde ich deshalb eben einfach mal kurz die Dinge aufzählen die ich bisher herausfinden konnte und dann ggf. dazu Nachfragen stellen. Vielleicht kann damit ja sogar auch noch der ein oder andere etwas anfangen?
(Ohne Eure Erlaubnis mach ich das natürlich trotzdem. Da kenn' ich ja nix.)

Übrigens dürfen natürlich auch gerne die Perl-Profis Antworten. Das ich jetzt selber PHP benutze spielt ja keine Rolle, müßten doch die generellen Probleme auch dort die gleichen sein. Denn mal los...

Punkt 1: 'Input'-Daten auf Gültigkeit überprüfen.
-------------------------------------------------
• Daten auf formale Richtigkeit prüfen.
• Daten die an externe Programme/die Shell/ oder kritische Funktionen ('eval();') gehen auf ungültige Zeichenfolgen prüfen. (z.B. '|' bei Daten an Sendmail) Bzw. prüfen das nur gültige Zeichenfolgen vorkommen.
• Wenn es sich um Pfadangaben zu Dateien/Verzeichnissen handelt prüfen ob nicht unerlaubterweise versucht wird den Dateipfad zu wechseln. Bsp. '../../../etc' o.ä.

FARGE: In wieweit macht es Sinn das oben gesagte auch auf eventuell vorhandene eignen (Text-) Konfigurationsdateien anzuwenden? Man weis ja nie... Oder gilt eher, wenn die erst manipuliert wurden ist es es schon zu spät?

Punkt 2: 'Environment'-Variablen prüfen.
----------------------------------------
• Konkret habe ich am Fall von PATH gelesen das man diese, wenn möglich, in seinen Script 'per Hand' setzen sollte wegen möglicher Manipulation.

FRAGE: Gehe ich also richtig davon aus, das den meisten anderen Environment-Variablen genau so wenig zu trauen ist und ich ähnlich gelagerte Evs grundsätzlich besser 'selber setzte'?

Punkt 3: Dateien/Dateihandling.
-------------------------------
• Dateien in die geschrieben werden soll in Unterverzeichnisse ablegen und nur in diesen Schreibzugriffe zulassen.
• Wenn übergebene Daten z.B. zur Generierung von HTML-Dateien benutzt werden darauf achten das keine 'aktiven Inhalte' wie eingebetetes PHP oder auch SSI darin vorkommen. (Bsp. PHP-Dateien, da dort möglicherweise ein „echo phpinfo();" drinnen stehen könnte, das Auskunft über die interne Struktur des Servers liefert)
Alternative im Verzeichnis der generierten Dateien keine aktiven Inhalte zulassen.
• Wen in Dateien geschrieben wird FLOCK/File-Locking benutzen. Atomare Zugriffe gewährleisten.

FRAGE: Wo kann ich ins besondere zum letzten Punkt (FLOCK ,... und wie man dieses am besten sicherstellt) nähere Informationen finden?

Punkt 4: Datei-Upload.
----------------------
• Überprüfen ob korrektes Dateiformat. Z.B. über die MimeType-Angabe.
• Auf Dateigröße überprüfen. (Beschränkungen der Dateigröße ins Programm fest verdrahten und sich nicht auf 'Hidden-Formular-Fields' mit der gespeicherten Größe verlassen.)
• Alles unter Punkt 3 aufgeführtes.

FRAGE: Die MimeType-Angabe ist doch bestimmt auch nicht gerade die sicherste Methode das Dateiformat zu prüfen, oder? Die wird doch vom Browser mit übergeben, weshalb da im Prinzip doch beliebiges drin auftauchen könnte. Wäre also eine Überprüfung auf Dateiendungen nicht sinnvoller?

Punkt 5: Sonstiges.
-------------------
• Auf Buffer-Overflow achten.
FRAGE: In wieweit Betrifft das noch Scriptsprachen? In PHP z.B. kann man eh keine explizite Größe von Variablen festlegen und zweitens scheinen ihn übergroße Werte nicht zu sonderlich zu stören (Quick-Test von eben) sondern er begrenzt diese Werte automatisch.

FRAGE: Andere Frage, ähnliches Thema. Was ist, wenn ich den Script übergroße Mengen an Daten (z.B. per GET) zuschicke? Glaube irgendwo einmal gelesen zu haben das man damit die Programme wunderbar abschießen können soll. Wenn ja, was kann man dagegen machen? Ist das Script nicht schon gecrasht bevor ich überhaupt dazu gekommen bin eventuelle Prüfungen auf Buffer-Overflows durchzuführen?

• Wichtige (Konfigurations-) Daten (z.B. Paßworte) immer verschlüsseln.

FRAGE: [Nur PHP?] Sollten wichtige (Konfigurations-) Daten nicht in 'ausführbare Dateien' abgelegt werden? Die Nachfrage bezieht sich auf ein (Forums-) Script (in PHP geschrieben) das ich vor einiger Zeit gefunden hatte. Dort hatte der Autor seine ganzen Konfigurationsdaten in einer *.inc Datei als normale Variablen in der Form „$var = wert;" deklariert. (So übrigens auch beim unverschlüsselten Paßwort) Nun soll es aber mit PHP laut Handbuch per 'Include' auch erlaubt sein Dateien auf fremden Servern in seine Scripte einzubinden. Würde das nicht bedeuten das ich mir in aller Seelenruhe diese Datei in mein eigenes Miniscript linken kann, um mir dann alle Werte ausgeben zu lassen? Oder habe ich da im PHP-Handbuch etwas falsch verstanden?

Sollte jemand mit lesen bis hierhin gekommen sein und dann auch noch die Muße finden zu antworten, dann schon einmal im Voraus vielem Dank.
Welche ganz wichtigen Aspekte sind mir also bisher entgangen? Auch Links zu weiterführenden Artikel sind immer gerne willkommen. (Wenn es nicht gerade die unter [1*] genanten sind. Die kenn' ich schon. :o) )

Mfg,
S(*schnarch*)önke

[1*] http://www.xwolf.com/
     http://stars.com/Authoring/Scripting/Security/
     http://www.go2net.com/people/paulp/cgi-security/safe-cgi.txt

  1. Punkt 1: 'Input'-Daten auf Gültigkeit überprüfen.

    • Daten auf formale Richtigkeit prüfen.
    • Daten die an externe Programme/die Shell/ oder kritische Funktionen ('eval();') gehen auf ungültige Zeichenfolgen prüfen. (z.B. '|' bei Daten an Sendmail) Bzw. prüfen das nur gültige Zeichenfolgen vorkommen.
    • Wenn es sich um Pfadangaben zu Dateien/Verzeichnissen handelt prüfen ob nicht unerlaubterweise versucht wird den Dateipfad zu wechseln. Bsp. '../../../etc' o.ä.

    FARGE: In wieweit macht es Sinn das oben gesagte auch auf eventuell vorhandene eignen (Text-) Konfigurationsdateien anzuwenden? Man weis ja nie... Oder gilt eher, wenn die erst manipuliert wurden ist es es schon zu spät?

    Ich denke, solange die Serversicherheit gewährleistet ist, kannst du davon ausgehen, daß deine eigenen Daten in Ordnung sind. Es ist wesentlich einfacher, wenn User gefährliche Daten übergeben, als daß sie Dateien auf dem Server verändern. Wenn sie das können, müssen sie sich ja nicht auf die Konfigurationsdateien beschränken, sondern es können gleich viel bösartigere Dinge in die PHP-Dateien geschrieben werden.

    Punkt 2: 'Environment'-Variablen prüfen.

    • Konkret habe ich am Fall von PATH gelesen das man diese, wenn möglich, in seinen Script 'per Hand' setzen sollte wegen möglicher Manipulation.

    FRAGE: Gehe ich also richtig davon aus, das den meisten anderen Environment-Variablen genau so wenig zu trauen ist und ich ähnlich gelagerte Evs grundsätzlich besser 'selber setzte'?

    Die Sache mit PATH hat den Hintergrund, daß so verhindert wird, irgendwelche beliebigen Programme, die zufällig im PATH drinsind, auszuführen, ohne daß man weiß, wo sie sich befinden.

    Das Environment enthält ja z.B. Infos über den Browser, der gerade eine Datei anfordert - diese Information kannst du nicht künstlich selbst erzeugen. Du solltest allerdings von der Programmlogik her dich nicht auf diese Informationen verlassen. Referer kann man fälschen, User-Agents kann man fälschen, alles kann man fälschen.

    Punkt 3: Dateien/Dateihandling.

    Das überspringe ich mal. ;)

    Punkt 4: Datei-Upload.

    • Überprüfen ob korrektes Dateiformat. Z.B. über die MimeType-Angabe.
    • Auf Dateigröße überprüfen. (Beschränkungen der Dateigröße ins Programm fest verdrahten und sich nicht auf 'Hidden-Formular-Fields' mit der gespeicherten Größe verlassen.)
    • Alles unter Punkt 3 aufgeführtes.

    FRAGE: Die MimeType-Angabe ist doch bestimmt auch nicht gerade die sicherste Methode das Dateiformat zu prüfen, oder? Die wird doch vom Browser mit übergeben, weshalb da im Prinzip doch beliebiges drin auftauchen könnte. Wäre also eine Überprüfung auf Dateiendungen nicht sinnvoller?

    Der Mime-Typ wird vom Browser meist garnicht gesendet. Jedenfalls nicht unbedingt einer, der den Inhalt der eindeutig und korrekt beschreibt. Den benutzt du besser nicht.

    Die Prüfung der Dateiendung ist aber genauso anfällig, denn das sind ja auch User-beeinflußbare Informationen. Es ist ohne Probleme möglich, einen Virus in "bild.jpg" umzubenennen. Wenn man den dann irgendwie zur Ausführung bringen kann (zurückbenennen, starten)...

    Sicherheit ist nur dann gegeben, wenn du das Datei*format* explizit prüfst. Oder die übergebenen Dateien wirklich nur auf ungefährliche Weise verwendest, also z.B. immer nur als Bild referenzierst.

    Die Dateigröße wird in der PHP.INI begrenzt: Default 2MB. PHP selbst hat die korrekte Information, wie groß die Datei wirklich ist, also kannst du dich darauf beziehen und mußt keine Formularfelder einbeziehen.

    Punkt 5: Sonstiges.

    • Auf Buffer-Overflow achten.
    FRAGE: In wieweit Betrifft das noch Scriptsprachen? In PHP z.B. kann man eh keine explizite Größe von Variablen festlegen und zweitens scheinen ihn übergroße Werte nicht zu sonderlich zu stören (Quick-Test von eben) sondern er begrenzt diese Werte automatisch.

    Buffer-Overflow ist für die Programmierer von Webservern und PHP ein Thema, nicht für die Programmierer, die PHP als Sprache benutzen - würde ich mal ganz unvorsichtig sagen. Als Serveradmin sollte man natürlich immer entsprechende Patches installieren.

    FRAGE: Andere Frage, ähnliches Thema. Was ist, wenn ich den Script übergroße Mengen an Daten (z.B. per GET) zuschicke? Glaube irgendwo einmal gelesen zu haben das man damit die Programme wunderbar abschießen können soll. Wenn ja, was kann man dagegen machen? Ist das Script nicht schon gecrasht bevor ich überhaupt dazu gekommen bin eventuelle Prüfungen auf Buffer-Overflows durchzuführen?

    Ist ein Problem des Webservers, nicht eines von PHP.

    • Wichtige (Konfigurations-) Daten (z.B. Paßworte) immer verschlüsseln.

    FRAGE: [Nur PHP?] Sollten wichtige (Konfigurations-) Daten nicht in 'ausführbare Dateien' abgelegt werden? Die Nachfrage bezieht sich auf ein (Forums-) Script (in PHP geschrieben) das ich vor einiger Zeit gefunden hatte. Dort hatte der Autor seine ganzen Konfigurationsdaten in einer *.inc Datei als normale Variablen in der Form „$var = wert;" deklariert. (So übrigens auch beim unverschlüsselten Paßwort) Nun soll es aber mit PHP laut Handbuch per 'Include' auch erlaubt sein Dateien auf fremden Servern in seine Scripte einzubinden. Würde das nicht bedeuten das ich mir in aller Seelenruhe diese Datei in mein eigenes Miniscript linken kann, um mir dann alle Werte ausgeben zu lassen? Oder habe ich da im PHP-Handbuch etwas falsch verstanden?

    Man kann den Webserver so konfigurieren, daß er Zugriffe auf *.inc-Dateien generell verbietet. Das macht die Daten schon mal wesentlich sicherer, weil dann keiner ran kann außer über den FTP-Zugang oder das Ausführen eigener Skripte (was einen erfolgreichen Angriff voraussetzt, der dann ohnehin jede Tür geöffnet hat).

    Das mit dem Include über Servergrenzen hinweg hab ich auch gerade gelesen (dachte eigentlich, daß es nicht geht - man lernt immer dazu), aber wenn der Server den Zugriff (und Directory-Listing) nicht erlaubt, ist das auch kein Thema. Man könnte ja auch den Browser nehmen und die inc-Datei als URL angeben.

    Soweit bis hierhin. Sicher kriege ich wegen meiner unqualifizierten Bemerkungen noch Schläge, aber das bin ich schon gewöhnt - so ist das hier.

    - Sven Rautenberg

    1. Morjen !

      Soweit bis hierhin. Sicher kriege ich wegen meiner unqualifizierten Bemerkungen noch Schläge, aber das bin ich schon gewöhnt - so ist das hier.

      .... und hier kommen sie schon ;-)

      FRAGE: Andere Frage, ähnliches Thema. Was ist, wenn ich den Script übergroße Mengen an Daten (z.B. per GET) zuschicke? Glaube irgendwo einmal gelesen zu haben das man damit die Programme wunderbar abschießen können soll. Wenn ja, was kann man dagegen machen? Ist das Script nicht schon gecrasht bevor ich überhaupt dazu gekommen bin eventuelle Prüfungen auf Buffer-Overflows durchzuführen?

      Ist ein Problem des Webservers, nicht eines von PHP.

      ... ist grundsätzlich nicht falsch, nur etwas locker formuliert. Denn um ein (weniger bekanntes) Zitat aus Götz von Berlichingen <cite>Wo viel Licht ist ist auch viel Schatten</cite> abzuwandeln:
      <cite>Wo viel Input ist ist auch viel Output</cite>

      Wenn also dein Skript den Server zumüllt weil es ungeprüft Daten ausgibt (wo ein GET da auch ein PUT) und der Provider dir daraufhin den Account sperrt verlagert sich das Problem eindeutig vom Webserver zu dir (also doch wieder ein PHP-Problem)

      Okay, ist nicht so ganz ernst gemeint, aber um diese Zeit ... ;-)

      MfG McNavc

  2. Gutes Nächtle Euch allen!

    Ja schlafe du auch gut ;)

    Punkt 1: 'Input'-Daten auf Gültigkeit überprüfen.

    • Daten auf formale Richtigkeit prüfen.
    • Daten die an externe Programme/die Shell/ oder kritische Funktionen ('eval();') gehen auf ungültige Zeichenfolgen prüfen. (z.B. '|' bei Daten an Sendmail) Bzw. prüfen das nur gültige Zeichenfolgen vorkommen.
    • Wenn es sich um Pfadangaben zu Dateien/Verzeichnissen handelt prüfen ob nicht unerlaubterweise versucht wird den Dateipfad zu wechseln. Bsp. '../../../etc' o.ä.

    FARGE: In wieweit macht es Sinn das oben gesagte auch auf eventuell vorhandene eignen (Text-) Konfigurationsdateien anzuwenden? Man weis ja nie... Oder gilt eher, wenn die erst manipuliert wurden ist es es schon zu spät?

    Konfigdateien sind ein heikles thema, da hier sensible daten drinne-
    stehen. Manipulation kannst du aber relativ einfach ausschließen;
    Als Schnellschuß würde ich vorschlagen, einen Haswert zu bilden,
    speichern und den beim einlesen vergleichen

    Punkt 2: 'Environment'-Variablen prüfen.

    • Konkret habe ich am Fall von PATH gelesen das man diese, wenn möglich, in seinen Script 'per Hand' setzen sollte wegen möglicher Manipulation.

    FRAGE: Gehe ich also richtig davon aus, das den meisten anderen Environment-Variablen genau so wenig zu trauen ist und ich ähnlich gelagerte Evs grundsätzlich besser 'selber setzte'?

    Bei $ENV{CONTENT_LENGTH} stelle ich mir schwierig vor. Aber wenn du
    den Path benötigst, und dein server feststeht schreibe ihn in deine
    Kocfig-Datei. Document Root etc. setze ich meistens von hand.

    Punkt 3: Dateien/Dateihandling.
    FRAGE: Wo kann ich ins besondere zum letzten Punkt (FLOCK ,... und wie man dieses am besten sicherstellt) nähere Informationen finden?

    perldoc -f flock ist recht informativ. In web.pm von xwolf ist ein
    anderes und evtl. flexibleres verfahren erklärt. Mir dünkt Wolfgang
    Wiese könnte hier mehr wissen ;)

    Punkt 4: Datei-Upload.

    • Überprüfen ob korrektes Dateiformat. Z.B. über die MimeType-Angabe.
    • Auf Dateigröße überprüfen. (Beschränkungen der Dateigröße ins Programm fest verdrahten und sich nicht auf 'Hidden-Formular-Fields' mit der gespeicherten Größe verlassen.)
    • Alles unter Punkt 3 aufgeführtes.

    FRAGE: Die MimeType-Angabe ist doch bestimmt auch nicht gerade die sicherste Methode das Dateiformat zu prüfen, oder? Die wird doch vom Browser mit übergeben, weshalb da im Prinzip doch beliebiges drin auftauchen könnte. Wäre also eine Überprüfung auf Dateiendungen nicht sinnvoller?

    Imho macht der browser zumindest solange er NN heist auch nur den
    Suffixtest. IE rät gemessen an SEINEN Maßstäben. Sinn und Unsinn
    seien dahingestellt. Wenn ich eine *.pl Datei *.jpg benenne kann sie
    trotzdem schaden machen. Letztendlich hängt die sicherheit auch an
    der Server-conf (endungs oder verzeichnisbeschränkte Ausführungs-
    rechte).
    Dateigröße prüfen ist immer wichtig und gut denke ich.
    Darüber hinaus will ich eigentlich immer wissen, wer bei mir files
    ablegt -> Zugangsbeschränkung

    Punkt 5: Sonstiges.

    • Auf Buffer-Overflow achten.
    FRAGE: In wieweit Betrifft das noch Scriptsprachen? In PHP z.B. kann man eh keine explizite Größe von Variablen festlegen und zweitens scheinen ihn übergroße Werte nicht zu sonderlich zu stören (Quick-Test von eben) sondern er begrenzt diese Werte automatisch.

    übergib mal ein 4mb binärfile an pack('u',$file). Da wirst du Ärger
    bekommen. Wenn die Dateien ein bestimmte größe überschreiten würde
    ich 'häppchenweise' vorgehen.

    FRAGE: Andere Frage, ähnliches Thema. Was ist, wenn ich den Script übergroße Mengen an Daten (z.B. per GET) zuschicke? Glaube irgendwo einmal gelesen zu haben das man damit die Programme wunderbar abschießen können soll. Wenn ja, was kann man dagegen machen? Ist das Script nicht schon gecrasht bevor ich überhaupt dazu gekommen bin eventuelle Prüfungen auf Buffer-Overflows durchzuführen?

    Etwas Mathe:
    Priviligierte haben max. 128kB/s Upload. Viel Server habe 90s Timeout
    für scripte. 128*90/8 = 1.3MB -> sollte machbar sein.
    Alles andere würde ich mit
    if ($ENV{CONTENT_LENGTH} > 1000000) {
        exit;}
    oder ähnlich abfangen.

    • Wichtige (Konfigurations-) Daten (z.B. Paßworte) immer verschlüsseln.

    FRAGE: [Nur PHP?] Sollten wichtige (Konfigurations-) Daten nicht in 'ausführbare Dateien' abgelegt werden? Die Nachfrage bezieht sich auf ein (Forums-) Script (in PHP geschrieben) das ich vor einiger Zeit gefunden hatte. Dort hatte der Autor seine ganzen Konfigurationsdaten in einer *.inc Datei als normale Variablen in der Form „$var = wert;" deklariert. (So übrigens auch beim unverschlüsselten Paßwort) Nun soll es aber mit PHP laut Handbuch per 'Include' auch erlaubt sein Dateien auf fremden Servern in seine Scripte einzubinden. Würde das nicht bedeuten das ich mir in aller Seelenruhe diese Datei in mein eigenes Miniscript linken kann, um mir dann alle Werte ausgeben zu lassen? Oder habe ich da im PHP-Handbuch etwas falsch verstanden?

    Wie du vielleicht bemerkt hast ist php nicht meine stärke.....
    Weiß ich nicht.

    Aber denk mal über folgendes nach. Passworte kann =~ s/kann/sollte/g
    man hashen. Wenn du aber Konfiguration verschlüsselst, musst du
    irgendwo deinen Key ablegen oder jedesmal vom client senden lassen,
    der dir was husten wird.
    Hier muss halt für gute sicherung deines cgi-bin gesorgt sein.

    HTH

    Bye Ed X

  3. Sup!

    Ich dachte, PHP würde als Apache-Modul über die Apache API laufen und nicht als CGI?
    XWolf gibt sich doch auf seiner Seite wohl kaum mit PHP ab?

    Würde mich ja ARG wundern.

    Gruesse,

    Bio

    (Perl rules!)

    1. Moin Bio!

      Ich dachte, PHP würde als Apache-Modul über die Apache API laufen und nicht als CGI?

      Und ich dachte Du würdest Dich immer mit den 'Feind' auskennen. PHP kannst Du sowohl als Apache Modul laufen lassen, wie auch als CGI. Hängt ganz nach Lust und Laune des Providers ab.

      XWolf gibt sich doch auf seiner Seite wohl kaum mit PHP ab?
      Würde mich ja ARG wundern.

      Klarer Fall von „Bio hat recht". Der Link zu Xwolf ist auch irgendwie verstümmelt. Hat wohl jemand dran herum geknabbert. Eigentlich sollte er auf den CGI Security Artikel dort verweisen. Und sich über grundsätzliches zu informieren schadet ja nie, gell.

      Nur - kleine Zwischenfrage - was hat das alles mit meiner Frage(n) zu tun? Außer natürlich das es in Perl keine Sicherheitsprobleme gibt, denn Perl ist Gut und PHP Böse. :) Nun ja, war ja auch schon spät in der Nacht als Du geantwortet hast. Es sei Dir also verziehen.

      Zum Schluß noch einen Keks für unseren Ritter. http://www.heise.de/tp/deutsch/inhalt/glosse/9351/1.html

      Tschüss,
      Sönke

      1. Sup!

        Klarer Fall von ,,Bio hat recht". Der Link zu Xwolf ist auch irgendwie verstümmelt. Hat wohl jemand dran herum geknabbert. Eigentlich sollte er auf den CGI Security Artikel dort verweisen. Und sich über grundsätzliches zu informieren schadet ja nie, gell.

        Sicher sicher ;-)

        Nur - kleine Zwischenfrage - was hat das alles mit meiner Frage(n) zu tun? Außer natürlich das es in Perl keine Sicherheitsprobleme gibt, denn Perl ist Gut und PHP Böse. :) Nun ja, war ja auch schon spät in der Nacht als Du geantwortet hast. Es sei Dir also verziehen.

        Hmm... tja... also... ich wollte mal dafür sorgen, daß alles klargestellt wird - schließlich haben jetzt alle gelernt, daß PHP auch als CGI laufen kann ;-) Und daß Perl gut ist und PHP böse. Abgesehen davon, daß es sicher bald etwas noch besseres als PHP geben wird (hab's heute gesehen... aber wer weiss ob's als freie Software rauskommt...) ... anyway...

        Zum Schluß noch einen Keks für unseren Ritter. http://www.heise.de/tp/deutsch/inhalt/glosse/9351/1.html

        Ich maaaaag Kekse! (kennt jemand dieses Lied "Krümelmonster - Ich mag Kekse" - irgendso eine Dance-Scheisse?)

        Gruesse,

        Bio

  4. Moin

    Punkt 1: 'Input'-Daten auf Gültigkeit überprüfen.

    * Daten auf formale Richtigkeit prüfen.
    * Daten die an externe Programme/die Shell/ oder kritische Funktionen ('eval();') gehen auf ungültige Zeichenfolgen prüfen. (z.B. '|' bei Daten an Sendmail) Bzw. prüfen das nur gültige Zeichenfolgen vorkommen.
    * Wenn es sich um Pfadangaben zu Dateien/Verzeichnissen handelt prüfen ob nicht unerlaubterweise versucht wird den Dateipfad zu wechseln. Bsp. '../../../etc' o.ä.

    Das Prüfen der Daten ist sicherlich sehr wichtig. Bei mir laufen Skripte in der Regel nicht weiter ohne das alle übergebenen Daten überprüft wurden. Wenn dabei was grob böses passiert, also etwas das auf absichtliche Manipulation schließen lässt, wird der Browser auf eine ungefährliche Seite (meist index.php) umgeleitet und das Skript beendet. Bei einfachen Fehlern, wenn der Benutzer Angaben vergessen hat oder so, bekommt der Benutzer eine Fehlermeldung und erhält die Chance seine Daten zu korrigieren.

    Im Übrigen benutze ich die Magic Quotes von PHP. Am Anfang aller Skripte wird eine Datei includiert die get_magic_quotes_gpc() abfragt und das escapen gegebenenfalls nachholt, falls der Admin diese Option in der Konfigurationsdatei abgeschaltet haben sollte. Danach kann ich mich darauf verlassen, dass keine Variable mehr ein unescaptes " oder ' enthält. Wenn man also im Folgenden alle Aufrufe von externen Programmen richtig macht - alle übergegebenen Parameter in Anführungszeichen setzen - sollte es keine Probleme mehr geben, auch mit den ausgefallensten Sonderzeichen. Das gilt auch für Datenbankabfragen! Mit dem mysql-Support von PHP ist es zwar nicht möglich mehrere Abfragen in einen mysql_query-Aufruf zu packen, aber das könnte sich ja ändern. Ein vernünftig escapter String, der in dem mysql_query-Aufruf in Anführungszeichen eingeschlossen ist, sorgt dafür dass kein böswilliger Benutzer etwas wie ";DROP DATABASE bla in einer Variablen verwendet.

    Ein anderer Punkt der gerne gegen die Sicherheit von PHP ins Feld geführt wird ist der, dass vom Benutzer übergebene Variablen ohne weiteres zutun des Progammierers global im PHP-Skript gesetzt werden. Dagegen hilft es einfach dafür zu sorgen, dass alle Variablen die intern verwendet werden, entweder garantiert vernünftig initialisiert werden oder am Anfang des Skriptes unset()ed werden.

    Das Problem mit dem PHP- oder HTML-Code in Usereingaben ist relativ einfach zu lösen: Ich habe immer eine Funktion definiert die nichts anderes macht, als echo htmlentities(). In den Skripten werden alle Ausgaben von benutzerdefinierten Eingaben nur über diese Funktion ausgeführt. Ein böser Benutzer kann nun soviel PHP- und HTML-Code eingeben wie er will, er wird nur angezeigt werden und niemals ausgeführt. (eval() ist sowieso böse)

    FARGE: In wieweit macht es Sinn das oben gesagte auch auf eventuell vorhandene eignen (Text-) Konfigurationsdateien anzuwenden? Man weis ja nie... Oder gilt eher, wenn die erst manipuliert wurden ist es es schon zu spät?

    Wenn jemand Dateien auf dem Server verändern kann, kann er ganz andere Sachen machen. Sorge einfach dafür, dass dein Skript deine Konfigurationsdatei in jedem Falle einliest, so dass der Benutzer die dort angegebenen Variablen nicht überschreiben kann.

    Punkt 2: 'Environment'-Variablen prüfen.

    Kann ich nichts zu sagen.

    Punkt 3: Dateien/Dateihandling.

    * Dateien in die geschrieben werden soll in Unterverzeichnisse ablegen und nur in diesen Schreibzugriffe zulassen.
    * Wenn übergebene Daten z.B. zur Generierung von HTML-Dateien benutzt werden darauf achten das keine 'aktiven Inhalte' wie eingebetetes PHP oder auch SSI darin vorkommen. (Bsp. PHP-Dateien, da dort möglicherweise ein "echo phpinfo();" drinnen stehen könnte, das Auskunft über die interne Struktur des Servers liefert)

    s.o.
    Wenn ich benutzerdefinierte Sachen anzeigen will, packe ich sie meist in eine Datenbank und so kann beim Auslesen schonmal kein PHP-Code ausgeführt werden. Als Schutz vor HTML muss htmlentities() reichen.

    Punkt 4: Datei-Upload.

    * Überprüfen ob korrektes Dateiformat. Z.B. über die MimeType-Angabe.
    * Auf Dateigröße überprüfen. (Beschränkungen der Dateigröße ins Programm fest verdrahten und sich nicht auf 'Hidden-Formular-Fields' mit der gespeicherten Größe verlassen.)
    * Alles unter Punkt 3 aufgeführtes.

    FRAGE: Die MimeType-Angabe ist doch bestimmt auch nicht gerade die sicherste Methode das Dateiformat zu prüfen, oder? Die wird doch vom Browser mit übergeben, weshalb da im Prinzip doch beliebiges drin auftauchen könnte. Wäre also eine Überprüfung auf Dateiendungen nicht sinnvoller?

    Die Dateigrößenüberprüfung musst du in jedem Fall durchführen, alles andere ist nicht zuverlässig. Du solltest dich aber beim Dateityp weder auf die MimeType-Angabe (wird vom Benutzer geliefert) noch auf die Dateiendung (wird auch vom Benutzer geliefert) verlassen. Eine gute Möglichkeit den Dateityp zu überprüfen ist file(1), das auf den meisten *n*x-Maschinen vorhanden sein sollte.

    Um zu verhindern, dass der Benutzer den Dateiupload ganz weglässt und in einem Formularfeld den Namen einer Datei auf dem Server angibt, stellt PHP ja schon Funktionen wie is_uploaded_file() und move_uploaded_file() bereit.

    Punkt 5: Sonstiges.

    * Auf Buffer-Overflow achten.
    FRAGE: In wieweit Betrifft das noch Scriptsprachen? In PHP z.B. kann man eh keine explizite Größe von Variablen festlegen und zweitens scheinen ihn übergroße Werte nicht zu sonderlich zu stören (Quick-Test von eben) sondern er begrenzt diese Werte automatisch.

    FRAGE: Andere Frage, ähnliches Thema. Was ist, wenn ich den Script übergroße Mengen an Daten (z.B. per GET) zuschicke? Glaube irgendwo einmal gelesen zu haben das man damit die Programme wunderbar abschießen können soll. Wenn ja, was kann man dagegen machen? Ist das Script nicht schon gecrasht bevor ich überhaupt dazu gekommen bin eventuelle Prüfungen auf Buffer-Overflows durchzuführen?

    Buffer Overflows in PHP selbst fallen wirklich eher in den Bereich der PHP-Entwickler, da dein Skript wahrscheinlich zu nichts kommen wird. Vorher ist der Webserver oder der PHP-Interpreter weg.

    * Wichtige (Konfigurations-) Daten (z.B. Paßworte) immer verschlüsseln.

    FRAGE: [Nur PHP?] Sollten wichtige (Konfigurations-) Daten nicht in 'ausführbare Dateien' abgelegt werden? Die Nachfrage bezieht sich auf ein (Forums-) Script (in PHP geschrieben) das ich vor einiger Zeit gefunden hatte. Dort hatte der Autor seine ganzen Konfigurationsdaten in einer *.inc Datei als normale Variablen in der Form "$var = wert;" deklariert. (So übrigens auch beim unverschlüsselten Paßwort) Nun soll es aber mit PHP laut Handbuch per 'Include' auch erlaubt sein Dateien auf fremden Servern in seine Scripte einzubinden. Würde das nicht bedeuten das ich mir in aller Seelenruhe diese Datei in mein eigenes Miniscript linken kann, um mir dann alle Werte ausgeben zu lassen? Oder habe ich da im PHP-Handbuch etwas falsch verstanden?

    Warum man diese Dateien auf Teufel komm raus mit .inc enden lassen muss, ist mir auch nicht klar. Meine Konfigurationsdateien heissen config.php o.ä. Darin finden sich dann die Konfigurationsvariablen in einem PHP-Block. Es ist dann nicht mehr möglich diese Variablen auf irgendeine Weise von außerhalb auszulesen. (Es sei denn der Angreifer hat direkten Shellzugriff, und dann hasst du andere Probleme)
    Das mit dem include über HTTP ist zwar im Prinzip richtig, aber auch hier ist es nicht möglich die Variablen zu bekommen, da der PHP-Interpreter vorher den PHP-Block rausgeschmissen hat. Das einzige Problem dass es hier gibt, ist wenn der PHP-Interpreter versagt. Da gab es mal einen Bug in der PHP/Apache-Kombination mit dem man die PHP-Ausführung von aussen unter bestimmten Umständen abschalten konnte. Achte also darauf, dass du immer eine aktuelle Version hast.

    Was Passwörter angeht: Üblicherweise verwende packe ich einen MD5-Hash aus Benutzername und Passwort in die Datenbank. Damit dürfte es für einen Angreifer nicht - oder nur sehr schwer möglich - sein das Passwort irgendwie zu erfahren und zu benutzen. Da hierbei das Passwort im Klartext übermittelt werden muss, z.B. per HTTP-Auth, sollte man aber möglichst HTTPS verwenden.

    --
    Henryk Plötz
    Grüße von der Ostsee

    1. hi,

      schuechterne Zwischenfrage: haeltst Du so eine Variablenueberpruefung/Umwandlung fuer
      ausreichend (hier nur "GET"), oder baust Du noch weitere Bremsen ein?

      function checkMagics($str)
      {
       $str = get_magic_quotes_gpc()? $str : AddSlashes($str);
       return htmlentities($str);
      }

      reset($HTTP_GET_VARS);
      while(list($key,$val) = each($HTTP_GET_VARS))
      {
       $HTTP_GET_VARS[$key] = checkMagics($val);
      }

      Gruesse  Joachim

  5. Moin, Moin!

    Noch einmal vielen Dank allen die mir geantwortet haben. Da habe ich ja jetzt erst einmal einiges zu Lesen, Nachzuschlagen und zum Grübeln. Hab's ja auch nicht anders gewollt.  :)

    Mfg,
    Sönke