Patrick: Best practise: Formulardaten in DB schreiben

Hallo,

es ist ja hinlänglich bekannt, dass Formulardaten niemals ungeprüft weitergenutzt werden sollten.

Bei unterschiedlichen erwarteten Daten fallen diese Prüfmechanismen selbstverständlich anders aus. Allerdings: Einige Prüfvorgänge wiederholen sich doch immer wieder. Ich habe während meiner wenigen PHP Wochen sicherlich alle wichtigen einmal irgendwo gesehen oder gelesen.

Ich suche jetzt aber - vor dem Go Live meiner Umfrage zu meiner Diplomarbeit (PHP und MySQL) - sozusagen eine "Checklist", welche Prüfungen man auf jeden Fall bei generischen Eingaben vornehmen sollte.

Ganz allgemein ausgedrückt suche ich ein Mindest-X in:

<?php
$link=mysql_connect('xyz','tralala','dumdidu') or die ("No connection.");
mysql_select_db('tralala') or die ("Database not found.");
$userdata = $_REQUEST['formfield'];

// X

mysql_query("INSERT INTO results $column VALUES $userdata";);
mysql_close($link);
?>

Freue mich auf konstruktive Antworten... ;)

Grüße,
Patrick

  1. es ist ja hinlänglich bekannt, dass Formulardaten niemals ungeprüft weitergenutzt werden sollten.

    Nö, das ist nicht bekannt. Ich weiss das nicht, kenne Lösungen, da hat der erfassende Nutzer Narrenfreiheit, die Daten werden in VARCHAR-Felder gespeichert und später manuell weiterverarbeitet, wenn überhaupt.   ;)

    Oder anders formuliert, man prüft immer auf etwas.

    Also, bspw. will man SQL-Injection vermeiden oder die Daten für die Speicherung in einem RDBMS fitmachen, Datengrössen prüfen, empfangene angelegte Dateien prüfen (Pornofilter ;) etc..

    Standardprüffverfahren, die Standardprüfungen vornehmen, gibt es nicht.

    --
    "It depends."
    1. Oder anders formuliert, man prüft immer auf etwas.

      Also, bspw. will man SQL-Injection vermeiden oder die Daten für die Speicherung in einem RDBMS fitmachen, Datengrössen prüfen, empfangene angelegte Dateien prüfen (Pornofilter ;) etc..

      Ich erhalte eine Reihe von Texteingaben vom User (und einige Daten, die gewählte Checkboxen symbolisieren).

      Ich suche nach dem Mindest-Gerüst an Prüfungen, die einen anonymen Teilnehmer daran hindern, Unfug zu treiben - ihm/ihr aber die Möglichkeit gegen, normalen Text (inklusive / und ) einzugeben. Ist das nicht so etwas wie eine "Standardsituation"?

      Dinge, die mir einfallen, auf die ich prüfen sollte, sind:

      • SQL-Injection
      • HTML Special Chars (?)
      • ... ?

      Noch einmal anders formuliert: Bei aller Offenheit für Individual-Lösungen: WAS sollte ein gewissenhafter PHP Programmierer IMMER überprüfen, wie sollte er die erhaltenen Daten ggf. IMMER manipulieren, bevor er sie fröhlich in eine MySQL Datenbank schreibt - zur späteren Auswertung in diesem Fall?

      1. Noch einmal anders formuliert: Bei aller Offenheit für Individual-Lösungen: WAS sollte ein gewissenhafter PHP Programmierer IMMER überprüfen, wie sollte er die erhaltenen Daten ggf. IMMER manipulieren, bevor er sie fröhlich in eine MySQL Datenbank schreibt - zur späteren Auswertung in diesem Fall?

        Was heisst "sollte"? Er muss jedenfalls gar nichts prüfen und kann die empfangenen Daten irgendwo speichern.

        Du willst Dich gegen etwas schützen, also vermutlich möchtest Du vermeiden, dass ein eventuell involvierter Datenserver merkwürdige Sachen macht oder ein Betriebssystemaufruf ("EXEC") durch den Nutzer erfolgt oder das die Kontrolle über den Webserver übernommen wird.   LOL

        All das ist denkbar und sollte bearbeitet werden:

        • SQL-Injection vorbeugen
        • PHP-Dienst mit denjenigen Rechten ausführen lassen, die er benötigt (keinesfalls als Admin)
        • keine Betreibssystemaufrufe

        Ansonsten sind die zu speichernden daten auf Konsistenz zu prüfen, in Abhängigkeit Deiner Anforderungslage. Ein "Hund" passt schlecht in ein numerisches Feld, eine "2" schlecht als Datumswert und eine "Katze" schlecht in ein CHAR(4). Eine "134,545" schlecht in ein NUMERIC(18,2) - für Währungsbeträge, etc..

        1. Was heisst "sollte"? Er muss jedenfalls gar nichts prüfen und kann die empfangenen Daten irgendwo speichern.

          "sollte" heisst: Wenn dieser Programmierer diesen Code hier zur Diskussion stellt, erwarten ihn keine bissigen Kommentare dazu, weil er alles dem Forums-Commonsense entsprechend richtig gemacht hat.

          Du willst Dich gegen etwas schützen, also vermutlich möchtest Du vermeiden, dass ein eventuell involvierter Datenserver merkwürdige Sachen macht oder ein Betriebssystemaufruf ("EXEC") durch den Nutzer erfolgt oder das die Kontrolle über den Webserver übernommen wird.   LOL

          Letzteres ist in diesem konkreten Fall ein Problem des Hosting-Providers, die Pointe habe ich nicht verstanden ;)

          All das ist denkbar und sollte bearbeitet werden:

          • SQL-Injection vorbeugen

          okay!

          • PHP-Dienst mit denjenigen Rechten ausführen lassen, die er benötigt (keinesfalls als Admin)

          siehe oben/Hosting.

          • keine Betreibssystemaufrufe

          sowieso nicht.

  2. echo $begrüßung;

    Bei unterschiedlichen erwarteten Daten fallen diese Prüfmechanismen selbstverständlich anders aus. Allerdings: Einige Prüfvorgänge wiederholen sich doch immer wieder. Ich habe während meiner wenigen PHP Wochen sicherlich alle wichtigen einmal irgendwo gesehen oder gelesen.

    Es gibt nur sehr wenige allgemeine Prüfungen, die noch dazu auch nicht ständig anzuwenden sind. Allgemein gesagt prüft man ja die Werte gegen seine Erwartungen. Erwartet man Zahlen, prüft man auf gültige Zahlenwerte. Erwartet man Zahlen in einem bestimmten Bereich, prüft man auch noch auf den Bereich. Datums- und Zeitwerte kann man auf Gültigkeit und auf Bereichseinhaltung prüfen.

    Ganz allgemein ausgedrückt suche ich ein Mindest-X in:

    Da es das nicht geben kann, beschränke ich mich auf einige Kommentare zu deinem Code

    $link=mysql_connect('xyz','tralala','dumdidu') or die ("No connection.");
    mysql_select_db('tralala') or die ("Database not found.");

    Es ist im Allgemeinen keine gute Idee, beim Auftreten von Fehlern schnell davonzurennen, und den Anwender vor dem Scherbenhaufen, zu dem er meist nichts kann, sitzen zu lassen.

    $userdata = $_REQUEST['formfield'];

    Immer wieder zu sehen: Die Unsitte des unnötigen Umkopierens.

    mysql_query("INSERT INTO results $column VALUES $userdata";);

    Hier fehlt keine Prüfung sondern eine kontextspezifische Kodierung. Und das ist auf alle Fälle ein Vorgang, der ausnahmslos immer stattzufinden hat.

    echo "$verabschiedung $name";

    1. $link=mysql_connect('xyz','tralala','dumdidu') or die ("No connection.");
      mysql_select_db('tralala') or die ("Database not found.");

      Es ist im Allgemeinen keine gute Idee, beim Auftreten von Fehlern schnell davonzurennen, und den Anwender vor dem Scherbenhaufen, zu dem er meist nichts kann, sitzen zu lassen.

      Ich weiss. Es ging mir in diesem skizzierten Beispiel aber eben um den Punkt der Eingabe-Validierung/Überprüfung. Es ging mir weniger um die Anwenderfreundlichkeit.

      $userdata = $_REQUEST['formfield'];

      Immer wieder zu sehen: Die Unsitte des unnötigen Umkopierens.

      Dito: Es ging mir um etwas anderes. Hätte ich $_REQUEST['formfield'] direkt in den Query geschrieben, hätte auch wer gemoppert - ausserdem hätte dann meine Frageformulierung derart nicht funktioniert.

      mysql_query("INSERT INTO results $column VALUES $userdata";);

      Hier fehlt keine Prüfung sondern eine kontextspezifische Kodierung. Und das ist auf alle Fälle ein Vorgang, der ausnahmslos immer stattzufinden hat.

      also mysql_real_escape_string($String) ?

      1. $userdata = $_REQUEST['formfield'];

        Immer wieder zu sehen: Die Unsitte des unnötigen Umkopierens.

        Dito: Es ging mir um etwas anderes. Hätte ich $_REQUEST['formfield'] direkt in den Query geschrieben, hätte auch wer gemoppert - ausserdem hätte dann meine Frageformulierung derart nicht funktioniert.

        Moppern? Möppeln kenn ich. Aber Du hast immer noch nicht kapiert, dass man nicht prüft um zu prüfen, sondern immer einen konkreten Anlass haben muss. Ein "best practise" gibt es hier nicht.

        1. $userdata = $_REQUEST['formfield'];

          Immer wieder zu sehen: Die Unsitte des unnötigen Umkopierens.

          Dito: Es ging mir um etwas anderes. Hätte ich $_REQUEST['formfield'] direkt in den Query geschrieben, hätte auch wer gemoppert - ausserdem hätte dann meine Frageformulierung derart nicht funktioniert.

          Moppern? Möppeln kenn ich.

          Klasse, damit haben wir je ein neues Wort gelernt heute abend! Wie sieht's aus mit Mosern?

          Aber Du hast immer noch nicht kapiert, dass man nicht prüft um zu prüfen

          Doch :-) Du magst es mir nicht glauben, aber das begreife ich.

          sondern immer einen konkreten Anlass haben muss.

          Ich versuchte lediglich herauszufinden, ob ich nicht irgendwelche konkreten Anlässe, die typischerweise in einer typischen Situation auftreten, vergessen habe.

          Ein "best practise" gibt es hier nicht.

          Warum werden dann Code-Auszüge wie:

          mysql_query("INSERT INTO results $column VALUES {$_REQUEST['data']}";);

          immer bemängelt?

          Deiner Logik zufolge wäre obiges bestens in Ordnung - solange es keinen konkreten Anlass zu weiterem Prüfen gibt. Das entspricht aber nicht dem Tenor im Forum hier.

          1. Ein "best practise" gibt es hier nicht.

            Warum werden dann Code-Auszüge wie:

            mysql_query("INSERT INTO results $column VALUES {$_REQUEST['data']}";);

            immer bemängelt?

            Deiner Logik zufolge wäre obiges bestens in Ordnung - solange es keinen konkreten Anlass zu weiterem Prüfen gibt. Das entspricht aber nicht dem Tenor im Forum hier.

            SQL-Injection wurde ja schon erwähnt, das ist so zu sagen primär zu bearbeiten, wenn man mit einem Datenserver zusammenarbeitet.

            Übrigens gefallen mir die geschweiften Klammern nicht. Funzt sowas?

            Ansonsten vermisse ich die Prüfung, ob mysql_query() Fehler zurückgegeben hat.

            Robuster als "reines" SQL sind übrigens immer die so genannten stored procedures.

            Und der Tenor des Forums bin natürlich ich, ein paar Bässe und Baritone und Frauenstimmen mögen dabei sein, aber der Meinungshengst hier bin ich!!!

            1. Hallo,

              Übrigens gefallen mir die geschweiften Klammern nicht. Funzt sowas?

              Ja

              Grüße,
              Willi

              1. Übrigens gefallen mir die geschweiften Klammern nicht. Funzt sowas?
                Ja

                Der SQL-sprechende Datenserver könnte aber meckern, wenn die runden Klammern fehlen, oder?   ;)

            2. Übrigens gefallen mir die geschweiften Klammern nicht. Funzt sowas?

              Das tun sie. Den Link dazu hat Willi gepostet. Neben dem funktionalen Aspekt gefällt mir diese Notation auch, weil ich in längeren Queries (bzw. Strings im Allgemeinen) schneller die Abgrenzung zwischen String-Inhalt und zu parsenden Variablen erkennen kann. Ob das den Datenmüll von jeweils zwei zusätzlichen Zeichen rechtfertigt... weiss ich auch nicht.

              Robuster als "reines" SQL sind übrigens immer die so genannten stored procedures.

              Mein Provider hat PHP5 ohne mysqli kompiliert - aber bei einem größeren Projekt als dieser Umfrage gerade würde ich auch auf stored procedures Wert legen.

              Und der Tenor des Forums bin natürlich ich, ein paar Bässe und Baritone und Frauenstimmen mögen dabei sein, aber der Meinungshengst hier bin ich!!!

              ;-)  Eisklar..

              Schönen Abend..

      2. echo $begrüßung;

        $link=mysql_connect('xyz','tralala','dumdidu') or die ("No connection.");
        mysql_select_db('tralala') or die ("Database not found.");
        Es ist im Allgemeinen keine gute Idee, beim Auftreten von Fehlern schnell davonzurennen, und den Anwender vor dem Scherbenhaufen, zu dem er meist nichts kann, sitzen zu lassen.
        Ich weiss. Es ging mir in diesem skizzierten Beispiel aber eben um den Punkt der Eingabe-Validierung/Überprüfung. Es ging mir weniger um die Anwenderfreundlichkeit.

        Das ist mir schon klar, man kann sich aber auch bei Beispielen um einen guten Stil bemühen, wenigstens angedeutet:

        if ($link = mysql_connect(...)) {  
          if (mysql_select_db(...), $link) {  
            ...  
          } else Fehlerbehandlung;  
        } else Fehlerbehandlung;
        

        $userdata = $_REQUEST['formfield'];
        Immer wieder zu sehen: Die Unsitte des unnötigen Umkopierens.
        Dito: Es ging mir um etwas anderes.

        Ja doch :-) Dazu hatte ich mich ja auch geäußert, worauf du aber nicht weiter eingegangen bist.

        Hätte ich $_REQUEST['formfield'] direkt in den Query geschrieben, hätte auch wer gemoppert - ausserdem hätte dann meine Frageformulierung derart nicht funktioniert.

        Wie wäre es mit: $checkedData = what_here($_REQUEST['formfield']);

        mysql_query("INSERT INTO results $column VALUES $userdata";);
        Hier fehlt keine Prüfung sondern eine kontextspezifische Kodierung. Und das ist auf alle Fälle ein Vorgang, der ausnahmslos immer stattzufinden hat.
        also mysql_real_escape_string($String) ?

        In dem Fall ja, aber du fragtest nach generellen Dingen, also lautet die Antwort nur: kontextspezifisch.

        echo "$verabschiedung $name";

        1. Das ist mir schon klar, man kann sich aber auch bei Beispielen um einen guten Stil bemühen, wenigstens angedeutet:

          Ich werde mich bemühen.

          Wie wäre es mit: $checkedData = what_here($_REQUEST['formfield']);

          Cool - aber in dem Moment war ich so selbstverliebt, dass ich da nicht drauf gekommen bin und meine X Lösung total gut fand ;-)

          Schönen Abend...

          1. Wie wäre es mit: $checkedData = what_here($_REQUEST['formfield']);

            Cool - aber in dem Moment war ich so selbstverliebt, dass ich da nicht drauf gekommen bin und meine X Lösung total gut fand ;-)

            Das Auto-Schwule wird Dir hier baer ganz schnell abgewöhnt, machts der Lully nicht, machts der Dödel.   ;)

            1. Das Auto-Schwule wird Dir hier baer ganz schnell abgewöhnt, machts der Lully nicht, machts der Dödel.   ;)

              Ich habe zu Autos ein rein platonisches Verhältnis.

              1. Das Auto-Schwule wird Dir hier baer ganz schnell abgewöhnt, machts der Lully nicht, machts der Dödel.   ;)

                Ich habe zu Autos ein rein platonisches Verhältnis.

                Es heisst ja auch das Auto und nicht der Auto. Aber Vorsicht bei Bussen!

  3. Den mysql_real_escape_string hast du ja ohnehin bereits angesprochen. Wenn du deine Daten aber sauber und unabhängig von der Webservereinstellung speichern willst, dann musst du berücksichtigen, dass per magic_quotes unter Umständen schon escaped wurde.

    Ein anderer typischer Fehler wäre, dass die abfrage in zwei Schritten erfolgt (z.B. eine Vorschau) und dann hidden-input Felder nicht mehr überprüft werden.

    So viel fällt mir gerade ein.
    Grüße.

  4. Ahoi Patrick,

    Ganz allgemein ausgedrückt suche ich ein Mindest-X in:

    Wie schon gesagt musst du wissen was für eingaben du erwartest. Die eingaben des Users musst du dann gegen die erwartung prüfen.

    Dazu gehören z.B.

    • Mindest Feldlänge (Pflichtfelder)
    • Maximale Feldlänge
    • Bestimmtes Format (z.B. eMail)
    • Bestimmter Wert (nur Zahlen)
      usw.

    MfG