Sicherheit und Validierung der Eingabedaten

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Sicherheit und Validierung der Eingabedaten

    Hallo

    Es soll eine PHP Applikation erstellt werden, dafür habe ich mir nun zuerst einige Gedanken zur Sicherheit und zur Validierung der Eingabedaten gemacht. Die Anwendung soll u.a. einen Userbereich mit einem Anmeldeformular für selbigen enthalten.

    Ich möchte folgendermaßen vorgehen:
    (Auf dem Entwicklungs- als auch auf dem Zielserver ist magic_quotes_gpc = off)

    1) Formulareingaben werden entsprechend des erwarteten Typs geprüft:

    - Name: preg_match("/^[a-zA-ZÄÖÜßäöüéèêáàâ&-.\s]$/", $_POST['name']);

    - Email: preg_match("/^[A-Z0-9._%+-ÄÖÜäöü]+@[A-Z0-9.-ÄÖÜäöü]+\.[A-Z]{2,6}$/i", $_POST['mail'])

    - URL: preg_match("/^(http|https)\:\/\/[a-z0-9-.\/]$/i", $_POST['url'])

    - Passwort: Die Speicherung würde als MD5 Hash erfolgen: md5($_POST['password'].$salt)
    Hier möchte ich im Prinzip alle erdenklichen Zeichen zulassen, fürchte nur, daß es irgendwelche bösen Zeichen gibt, mit denen ich mir möglicherweise ein Loch ins Script reiße (Beispiel siehe [1]). So gesehen ist es vielleicht sinnvoller, das Passwort auch auf den Zeichenvorrat des Namens einzuschränken.

    - Textfeld: preg_match("/^[a-zA-Z0-9-ÄÖÜßäöü.,:!?\s\r\n]$/", $_POST['text'])

    Ist es notwendig, vor der Validierung mit preg_match() die Funktion strip_tags() anzuwenden?


    2) Wenn die unter 1) genannte Validierung fehlschlägt, wird das Formular erneut mit den bereits eingetragenen, möglicherweise bösen Werten angezeigt. Diese werden vor der Ausgabe noch einmal mit htmlentities() bearbeitet.


    3) Wenn alle Eingaben den regulären Ausdrücken entsprechen, werden die Daten in eine MySQL Datenbank eingetragen. Dazu nutze ich die unter [2] genannte erweiterte mysqli Klasse, welche mit Prepared Statements arbeitet.

    Bin ich hier wirklich sicher vor SQL Injections oder kann es unter irgendwelchen Umständen trotzdem dazu kommen, so daß weiterhin mit mysql(i)_real_escape_string gearbeitet werden sollte?


    4) Ist es ein Risiko, strtolower() auf eine ungeprüfte Variable anzuwenden? Gleiches wäre interessant für die Verarbeitung einer ungeprüften Variable in einer switch/case Anweisung.


    5) Ebenso könnte über die superglobale Variable $_SERVER unerwünschter Input eingeschleust werden. Genügt es hier, beispielsweise für den Useragent, addslashes($_SERVER['USER_AGENT']) anzuwenden oder reicht das nicht bzw. wäre eine andere Funktion sinnvoller? Kann auch $_SERVER['REMOTE_ADDR'] gefakt werden und sollte daher erst validiert werden?


    Erstmal vielen Dank an alle, die dieses lange Posting bis hier durchgelesen haben
    Ich bin für sinnvolle Tips, Anregungen und Ergängzungen zu der beschriebenen Vorgehensweise sowie für die Beantwortung der gestellten Fragen dankbar. Wenn jemand ein sicherheitstechnisches "Problem" entdeckt, beispielsweise ein fälschlicherweise zugelassenes böses Zeichen in einem der regulären Ausdrücke, bin ich ebenfalls für einen Hinweis dankbar.

    [1] http://www.phpbb.de/community/viewtopic.php?t=110637
    [2] http://www.robpoyntz.com/blog/?p=191

  • #2
    Re: Sicherheit und Validierung der Eingabedaten

    Original geschrieben von h3llo
    - Passwort: Die Speicherung würde als MD5 Hash erfolgen: md5($_POST['password'].$salt)
    Hier möchte ich im Prinzip alle erdenklichen Zeichen zulassen, fürchte nur, daß es irgendwelche bösen Zeichen gibt, mit denen ich mir möglicherweise ein Loch ins Script reiße (Beispiel siehe [1]). So gesehen ist es vielleicht sinnvoller, das Passwort auch auf den Zeichenvorrat des Namens einzuschränken.
    Nein.
    Ich wuesste nicht, welche Zeichen das sein sollten.

    Wenn man ueberhaupt die zulaessigen Zeichen fuer die Wahl eines Passwortes einschraenkt, dann macht man das aus anderen Gruenden - z.B. koennte man Umlaute verbieten, weil diese problematisch werden, wenn der Nutzer sich mal von einem Rechner mit nicht-deutscher Tastatur aus einloggen will.

    Ist es notwendig, vor der Validierung mit preg_match() die Funktion strip_tags() anzuwenden?
    Was wuerdest du dir davon versprechen?

    strip_tags sollte man meiner persoenlichen Meinung nach "nie" verwenden - es taugt nichts, und macht unter Umstaenden mehr "kaputt", als es hilft.
    "Tags" braucht man nicht herauszufiltern - vielleicht will der Nutzer ja irgendwas posten, was HTML-Beispielcode enthaelt, in einem Forum wie diesem hier zum Beispiel - da waere es doch saubloede, wenn das per strip_tags bearbeitet wuerde.

    Allerdings sind Zeichen, die in HTML Sonderbedeutung haben, natuerlich entsprechend zu behandeln; Stichwort htmlspecialchars.

    2) Wenn die unter 1) genannte Validierung fehlschlägt, wird das Formular erneut mit den bereits eingetragenen, möglicherweise bösen Werten angezeigt. Diese werden vor der Ausgabe noch einmal mit htmlentities() bearbeitet.
    Bei Verwendung einer passenden Zeichenkodierung reicht htmlspecialchars aus.

    3) Wenn alle Eingaben den regulären Ausdrücken entsprechen, werden die Daten in eine MySQL Datenbank eingetragen. Dazu nutze ich die unter [2] genannte erweiterte mysqli Klasse, welche mit Prepared Statements arbeitet.

    Bin ich hier wirklich sicher vor SQL Injections oder kann es unter irgendwelchen Umständen trotzdem dazu kommen, so daß weiterhin mit mysql(i)_real_escape_string gearbeitet werden sollte?
    Bei der Nutzung von prepared statements ist das nicht noetig.

    Der Grund, warum man mysql_real_escape_string bei einem "normalen" Statement verwendet ist der, dass dort Befehlsbestandteile und Daten "in einem" uebertragen werden, und daher sichergestellt werden muss, dass Daten von der Datenbank-Schnittstelle nicht mit Befehlsbestandteilen verwechselt werden.

    Bei prepared statements werden die Daten jedoch getrennt vom Befehlsteil des Statements uebertragen, also muss man sich hier nicht noch extra um sowas kuemmern.

    4) Ist es ein Risiko, strtolower() auf eine ungeprüfte Variable anzuwenden? Gleiches wäre interessant für die Verarbeitung einer ungeprüften Variable in einer switch/case Anweisung.
    Das "Risiko" bei strtolower auf einen ungeprueften Wert ist, dass du dann die klein geschriebene Version dieses ungeprueften Wertes bekommst. Klingt das sonderlich gefaehrlich ...?

    Bei switch/case sollte man natuerlich aufpassen, welche Werte ggf. in den default-Case reinlaufen.
    Und auch was die automatische Typkonvertierung von PHP bei Vergleichen unterschiedlicher Datentypen angeht, lauert da manchmal der ein oder andere Fallstrick.

    5) Ebenso könnte über die superglobale Variable $_SERVER unerwünschter Input eingeschleust werden. Genügt es hier, beispielsweise für den Useragent, addslashes($_SERVER['USER_AGENT']) anzuwenden oder reicht das nicht bzw. wäre eine andere Funktion sinnvoller?
    Ob ein Wert "gefaehrlich" sein kann oder nicht, kommt immer darauf an, was du mit diesem Wert machst.

    Die Szenarios, in denen addslashes sinnvoll sein koennte, duerften allerdings verschwindend gering sein. (Das meintest du doch hoffentlich nicht in Bezug auf die Verwendung in einer MySQL-Query?)

    Kann auch $_SERVER['REMOTE_ADDR'] gefakt werden und sollte daher erst validiert werden?
    Validiert gegen was?


    ----------

    Grundsaetlich gilt beim Umgang mit Daten immer:
    Wann immer du einen Wert in einen Kontext ueberfuehrst, musst du ihn kontextspezifisch behandeln.
    I don't believe in rebirth. Actually, I never did in my whole lives.

    Kommentar


    • #3
      Re: Re: Sicherheit und Validierung der Eingabedaten

      Original geschrieben von wahsaga
      Ob ein Wert "gefaehrlich" sein kann oder nicht, kommt immer darauf an, was du mit diesem Wert machst.

      Die Szenarios, in denen addslashes sinnvoll sein koennte, duerften allerdings verschwindend gering sein. (Das meintest du doch hoffentlich nicht in Bezug auf die Verwendung in einer MySQL-Query?)
      Wenn ich den Useragent aus $_SERVER['USER_AGENT'] in der Datenbank speichern wollte, dann sehe ich durch Anwendung von Prepared Statements keinerlei Risiko.
      Für die Ausgabe würde ich noch einmal htmlentities() rüberlaufen lassen.
      Besteht hier trotzdem noch irgendein Risiko, beispielsweise auch dadurch, daß ich in einer Session mit dem Useragent arbeite (Vergleich Sessionwert <>$_SERVER['USER_AGENT']), der die Anwendung von addslashes erfordert?

      Original geschrieben von wahsaga
      Validiert gegen was?
      Ebenfalls per Regex prüfen, ob nur erlaubte Zeichen drin vorkommen, so daß nichts eingeschleust werden kann.



      6) Ich habe unter [1] einen Artikel zur Filterung der Session IDs gelesen. Der Inhalt des Session Cookies kann natürlich auch manipuliert werden. Ich arbeite allerdings nicht direkt mit der Session ID, sondern überlassen dies alleine PHP. Ich arbeite nur mit dem $_SESSION Array, so daß ich keinen wirklichen Grund für die Filterung der übermittelten session_id() sehe. Ist das korrekt oder habe ich dabei etwas übersehen?


      7) Beim testen mit folgender Email Regex
      PHP-Code:
      (preg_match("/^[A-Z0-9._-ÄÖÜäöü]+@[A-Z0-9.-ÄÖÜäöü]+\.[A-Z]{2,6}$/i",$email)) 
      fiel auf, daß der Ausdruck bei Angabe einer Testadresse direkt im Script matcht, nicht aber bei Übermittlung des selben Teststrings per Post-Methode.
      Beim Post konnte man beispielsweise \n an die Adresse anhängen oder auch mehrere @ Zeichen verwenden und der Ausdruck matchte trotzdem.
      Ich sehe zwar keine Grundlage für eine Email Injection, da :, %, & nicht matchen aber eine Erklärung für dieses Verhalten wäre schon interessant.


      [1] http://phpperformance.de/session-ids...rmant-filtern/

      Kommentar

      Lädt...
      X