Enrico: Absicherung von Formularen gegen schadhaftem Code

Hallo,

man soll ja immer mit Allem rechnen und somit auch damit, dass in Formularfelder schadhafter Code eingegeben wird.

Nun gibt es ja spezielle Frameworks, die aber sehr umfangreich sind und die ich nicht verstehe.

Ich möchte aber nichts verwenden, was ich nicht verstehe, da ich den Code dann nicht nachvollziehen kann.

Was spricht dagegen, einfach alle Zeichen und Befehle, die schadhaften Code einleiten bzw. beinhalten könnten, mittels preg_replace zu ersetzen, so wie nachfolgend auf ganz niedriger Ebene umgesetzt?

  
preg_replace('/[^A-ZÄÖÜa-zäöü0-9\?\1\(\)\.[space]{2,} _\-\+\&]/', '', $Wert);  

Schadhaften Code zu verschleiern macht desweiteren ja nur durch Verwendung von Zeichensatzcodierungen Sinn, da verschlüsselter Code nicht automatisch entschlüsselt und ausgeführt wird oder sehe ich das falsch?

Wenn dem so ist, dann müsste es ja ausreichen, die verschiedenen Zeichensatzcodierungen in lesbare Form zurückzuführen und dann den obigen preg_replace-Befehl auszuführen.

Wie seht ihr das?

Wäre meine Überlegung ein Ansatz, meine Formulare abzusichern?
Wie würdet ihr vorgehen?

Gruß,
Enrico

  1. Hi,

    man soll ja immer mit Allem rechnen und somit auch damit, dass in Formularfelder schadhafter Code eingegeben wird.

    die Antwort ist einfach. Schadhafte Daten (denn Nutzer geben Daten ein und nicht Code) müssen immer ihrem Kontext entsprechend behandelt werden. Im SQL-Kontext gibt es andere Daten, die zu Sicherheitslücken führen (das ' fällt hierbei ein), im HTML-Kontext sind es andere (<, >, welche deine Seite stark verändern können, wenn man nicht darauf aufpasst; & muss auch noch maskiert werden).

    Daher: wenn du Daten irgendwohin ausgibst, beachte den Kontextwechsel.

    Bis die Tage,
    Matti

    1. Hallo Matti,

      aber verhindert mein preg_replace in seiner einfachsten und strengsten Form nicht genau, dass ein Kontektwechsel stattfinden kann?

      Gruß,
      Enrico

      1. Tach!

        aber verhindert mein preg_replace in seiner einfachsten und strengsten Form nicht genau, dass ein Kontektwechsel stattfinden kann?

        Kontextwechsel bedeutet hier, dass Daten in einen anderen Kontext gebracht werden. Du fügst Daten in HTML-Code ein, du fügst Daten in Javascript-Code ein, du fügst Daten in ein SQL-Statement ein, du fügst Daten in ein Shell-Komamndo ein. Der Kontextwechsel ist immer da. Deine Aufgabe als verantwortungsvoller Programmierer ist es, die Daten für den jeweiligen Kontextwechsel entsprechend vorzubereiten. Teilweise muss man sogar noch feiner differenzieren. "SQL-Statement" ist zum Beispiel viel zu allgemein, da gibt es Strings, zusätzlich mit LIKE, da gibt es Bezeichner, und da gibt es Zahlen, von denen manche ohne Anführungszeichen notiert werden wollen.

        Wenn du alle Zeichen für alle potentiellen Kontexte beachten willst, dann musst du als Muster .* nehmen.

        Deine Aufgabe beim Entgegennehmen der Daten beschränkt sich lediglich auf eine fachliche Prüfung. Wenn beispielsweise eine Zahl erwartet wird, sollte is_numeric() entsprechend antworten oder du nimmst einfach intval()/floatval() zum Erzwingen. Es spielt dann auch keine Rolle, ob der Anwender 1E6 oder 1000000 oder 0xF4240 eingegeben hat.

        Zudem solltest du beachten, dass deine Prüfmöglichkeiten beschränkt sind. Eine nutzbare Email-Adresse lässt sich ebensowenig erkennen wie eingegebener aber den formalen Anforderungen genügender Müll.

        preg_replace('/[^A-ZÄÖÜa-zäöü0-9?\1().[space]{2,} _-+&]/', '', $Wert);

        Außerdem ist dein Regex fehlerhaft. [:space:] mit Doppelpunkten würde das heißen, aber ohne Wiederholungsangabe. In einer Zeichenklasse gelten die übrigen Regex-Regeln nicht mehr. Zum Beispiel stehen darin immer einzelne Zeichen (mit Ausnahme einiger Zeichentypen, wie \d, \D etc.). Zwei Leerzeichen hintereinander kannst du nicht in einer Zeichenklasse angeben. Die Zeichen {2,} stehen hier jedes für sich selbst. Zudem ist es nicht erforderlich, Sonderzeichen (mit Ausnahmen für , - und ^) zu maskieren.

        dedlfix.

      2. Hallo,

        aber verhindert mein preg_replace in seiner einfachsten und strengsten Form nicht genau, dass ein Kontektwechsel stattfinden kann?

        nein, der Kontextwechsel findet in jedem Fall statt - auch wenn dein RegEx möglicherweise die Daten so verändert, dass sie keinen Schaden anrichten. Btw, verwechsle bitte nicht die Begriffe "schadhaft" (ist selbst beschädigt) und "schädlich" (kann zu Schäden führen). Die im Formular eingegebenen Daten sind nicht schadhaft, wie du im Startposting formulierst, aber möglicherweise schädlich.

        Aber der springende Punkt ist doch: Du veränderst eingegebene Daten inhaltlich. Das möchte man aber nicht, und darum darf man bei jedem Kontextwechsel nur die genau darauf abgestimmten Maskierungen oder Codierungen vornehmen, die dafür sorgen, dass am Ende des Übermittlungswegs wieder exakt die Originaldaten zur Verfügung stehen.

        So long,
         Martin

        --
        Wer im Glashaus sitzt, sollte Spaß am Fensterputzen haben.
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
  2. Hallo,

    Danke für eure Anregungen und konkreten Tipps.

    Dann werde ich mich an deren Umsetzung machen.

    Gruß,
    Enrico

    1. Hallo,

      vor der Filterung vermeintlich schädlicher Eingaben möchte ich zunächst ein automatisiertes Versenden meiner Formulare durch Bots verhindern.

      Folgende Mechanismen habe ich bereits eingebaut:

      1. Die relevanten Textfelder werden mit verschlüsselten und einer Zufallszahl versehenen Bezeichnern über CSS in den Vordergrund gerückt. Die Fangfelder hingegen sind und bleiben leer, haben eindeutige und für Bots hoffentlich attraktive Bezeichner ("Name", "eMail",...) und werden mit "display: none;" ausgegeben. Sind die Fangfelder nach dem Abschicken gefüllt, dann war ein Bot am Werk.

      2. Ich frage die Zeitspanne ab, innerhalb derer die Formulare verschickt werden. Wird ein Formular innerhalb von 10 Sekunden abgeschickt, so war vermutlich ein Bot am Werk. Vergehen 15 Minuten bis zum Übermitteln, dann wird das Formular ebenfalls ungültig.

      Nun möchte ich final noch eine Sicherheitsabfrage nach folgendem Muster einbauen:

      "Bitte zähle alle Positionen der einzelnen Buchstaben im Alphabet des ersten Wortes dieser Sicherheitsabfrage zusammen und gebe die Zahl in das nachfolgende Textfeld ein. Dies dient der Abwehr automatisiert verschickter Formulare (Spam)."

      Wobei das abzufragende Wort variiert ("ersten", "zweiten", "dritten", "vierten",...).

      Ist dies beim ersten Lesen verständlich oder kann/sollte ich dies anders formulieren?

      Kann/sollte ich sonst noch etwas berücksichtigen, um ein automatisiertes Verschicken wirksam zu unterbinden (Filterlisten sind wohl viel zu umfangreich)?

      Vielen Dank und Gruß,
      Enrico

      1. Om nah hoo pez nyeetz, Enrico!

        "Bitte zähle alle Positionen der einzelnen Buchstaben im Alphabet des ersten Wortes dieser Sicherheitsabfrage zusammen und gebe die Zahl in das nachfolgende Textfeld ein. Dies dient der Abwehr automatisiert verschickter Formulare (Spam)."

        Darauf würde ich verzichten. Den anderen Ansatz finde ich nicht schlecht.

        Ist dies beim ersten Lesen verständlich oder kann/sollte ich dies anders formulieren?

        Ja ;-)

        Kann/sollte ich sonst noch etwas berücksichtigen, um ein automatisiertes Verschicken wirksam zu unterbinden (Filterlisten sind wohl viel zu umfangreich)?

        Vielleicht noch ein Häkchen, das entfernt werden muss.

        Matthias

        --
        1/z ist kein Blatt Papier.

        1. Hallo Matthias,

          Darauf würde ich verzichten

          Würdest Du auf so eine Abfrage generell verzichten oder nur auf die von mir genannte, weil sie, bei langen Wörtern, zu kompliziert und zeitaufwändig ist oder wäre sie durchaus sinnvoll, wenn ich sie  auf die kürzeren Worte ("Bitte", "der", "im",...) beschränken würde?

          Den anderen Ansatz finde ich nicht schlecht

          Nicht schlecht signalisiert mir, dass man hier noch was verbessern kann/könnte/sollte.
          Was würdest Du anders machen?

          Vielleicht noch ein Häkchen, das entfernt werden muss

          Bei einem Häkchen könnte ein Bot doch relativ leicht schnell dazulernen, oder?

          Gruß,
          Enrico

          1. Om nah hoo pez nyeetz, Enrico!

            Bei einem Häkchen könnte ein Bot doch relativ leicht schnell dazulernen, oder?

            Das wird immer dein Problem sein, Bots lernen.

            Matthias

            --
            1/z ist kein Blatt Papier.

            1. Hallo Matthias,

              Das wird immer dein Problem sein, Bots lernen

              Leider, leider

              Danke auf jeden Fall für die hilfreichen Anregungen (gilt natürlich auch für Martin).

              Ich werde mich wohl auf das reine Abzählen der Anzahl der Buchstaben eines zufällig ausgewählten Wortes beschränken, das sollte jeder können.

              Gruß,
              Enrico

              1. Om nah hoo pez nyeetz, Enrico!

                Ich werde mich wohl auf das reine Abzählen der Anzahl der Buchstaben eines zufällig ausgewählten Wortes beschränken, das sollte jeder können.

                Wie gesagt: Ich würde darauf verzichten. Das kommt natürlich auch immer auf den konkreten Anwendungsfall an, etwa darauf wieviele Datensätze du so pro Tag erwartest und was mit denen geschehen soll.

                Matthias

                --
                1/z ist kein Blatt Papier.

                1. Hallo Matthias,

                  nicht sichtbare Fangfelder, zufällig benannte Felder, Zeitlimit könnten auch reichen.

                  Wie gesagt: Ich würde darauf verzichten

                  Ok, lasse ich weg, die Einträge dürften sich, v.a. am Anfang, in Grenzen halten (wird "nur" ein kleiner Online-Shop von Privat)

                  Gruß,
                  Enrico

                  1. Om nah hoo pez nyeetz, Enrico!

                    Ok, lasse ich weg, die Einträge dürften sich, v.a. am Anfang, in Grenzen halten (wird "nur" ein kleiner Online-Shop von Privat)

                    also sitzt in der Endkontrolle sowieso ein Mensch, der die Aufträge bearbeitet.

                    Matthias

                    --
                    1/z ist kein Blatt Papier.

                    1. Hallo Matthias,

                      also sitzt in der Endkontrolle sowieso ein Mensch, der die Aufträge bearbeitet

                      Auf der Startseite werden Neuigkeiten angezeigt, die man dokumentieren kann.
                      Hier erfolgt die Übernahme der Kommentare nach Validierung und Bestätigung der Vorschau direkt.

                      Bei Anfragen werde ich genauso verfahren.

                      Bestellungen haben sowieso immer Zwischenschritte, die uns dann per E-Mail zugestellt werden.

                      Anfragen und Bestellungen tauchen im Online-Shop somit eh nicht auf.

                      Gruß,
                      Enrico

            2. Moin!

              Om nah hoo pez nyeetz, Enrico!

              Bei einem Häkchen könnte ein Bot doch relativ leicht schnell dazulernen, oder?

              Das wird immer dein Problem sein, Bots lernen.

              Die künstliche Intelligenz ist noch nicht erfunden. Insofern: Nein, Bots lernen nicht von alleine dazu. Es erfordert einen Programmierer, der ihnen besseres Verhalten beibringt. Und das wiederum erfordert, dass es einen wirtschaftlichen Vorteil bringt.

              Spam-Bekämpfung ist deshalb recht simpel: Es reicht, die Latte so hoch zu legen, dass nur noch ein vertretbar kleiner Anteil an Spam durchkommt. Captchas gehören nicht dazu, die werden von einer Armee von Dritte-Welt-Arbeitern für einen Hungerlohn erkannt und eingegeben. 1000 Captchas gelöst bekommen kostet einen Dollar.

              Solange es bessere Ziele gibt, die man bespammen kann, und die auch einfacher von Bots besucht werden, wird man kein Spamziel sein.

              Ich wundere mich beispielsweise immer noch, warum hier im Forum kein automatisierter Spam aufschlägt. Meine Vermutung: Die Hauptseite des Forums wird nicht von Suchmaschinen indiziert, weswegen der Einstieg zum Posten von Bots nicht gefunden wird. Dann ist das Formular durchaus "kompliziert", weil es die unterschiedlichsten Merkwürdigkeiten bemängelt. Es gibt auch zuviele Submit-Buttons, die nicht alle zum Ziel führen, und unangemeldet auch noch Pflicht-Checkboxen.

              Obwohl ich es also für absolut simpel halte, für dieses Forum einen Bot zu bauen, der Spam absondert, sind die existierenden Bots bislang an dieser Aufgabe gescheitert.

              - Sven Rautenberg

      2. Hi,

        1. Die relevanten Textfelder werden mit verschlüsselten und einer Zufallszahl versehenen Bezeichnern über CSS in den Vordergrund gerückt. Die Fangfelder hingegen sind und bleiben leer, haben eindeutige und für Bots hoffentlich attraktive Bezeichner ("Name", "eMail",...) und werden mit "display: none;" ausgegeben. Sind die Fangfelder nach dem Abschicken gefüllt, dann war ein Bot am Werk.

        kann man machen, hilft vermutlich schon ein ganzes Stück.

        1. Ich frage die Zeitspanne ab, innerhalb derer die Formulare verschickt werden. Wird ein Formular innerhalb von 10 Sekunden abgeschickt, so war vermutlich ein Bot am Werk. Vergehen 15 Minuten bis zum Übermitteln, dann wird das Formular ebenfalls ungültig.

        Auch okay, denke ich.

        "Bitte zähle alle Positionen der einzelnen Buchstaben im Alphabet des ersten Wortes dieser Sicherheitsabfrage zusammen und gebe die Zahl in das nachfolgende Textfeld ein. Dies dient der Abwehr automatisiert verschickter Formulare (Spam)."

        Du liebe Güte, viel zu kompliziert! Wäre das Wort beispielsweise "Ziegen", müsste man also 66 eingeben. Nicht nur, dass viele Menschen schlecht rechnen können; schon allein das Abzählen der Position im Alphabet ist eine Hürde, wenn man nicht zufällig die ASCII-Codes im Kopf hat und direkt ablesen kann.
        Abgesehen davon: Nicht "gebe", sondern "gib" oder "geben Sie".

        Ist dies beim ersten Lesen verständlich oder kann/sollte ich dies anders formulieren?

        Ich habe verstanden, was du willst (glaube ich), aber es ist bei weitem zu kompliziert. Das muss viel einfacher sein, etwa sowas:

        Welches Tier ist grün?
         1. Meerschweinchen
         2. Laubfrosch
         3. Schäferhund
         4. Rabe

        Viel höher würde ich den Schwierigkeitsgrad nicht ansetzen.

        Kann/sollte ich sonst noch etwas berücksichtigen, um ein automatisiertes Verschicken wirksam zu unterbinden (Filterlisten sind wohl viel zu umfangreich)?

        Je nachdem, wofür das Formular gedacht ist, könnte eine erzwungene Vorschau sehr hilfreich sein - also dass erst im zweiten Schritt die endgültige Aktion ausgelöst wird. Eventuell kann man dann sogar auf andere Kniffe verzichten.

        Ciao,
         Martin

        --
        Wer im Glashaus sitzt, sollte Spaß am Fensterputzen haben.
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        1. Hallo Martin,

          Hm, ja, doch, hast Recht.
          Ich sollte hier auf ganz einfache Fragen umsteigen.
          Evtl. sogar mit Variation der Position der richtigen Antwort.

          Abgesehen davon: Nicht "gebe", sondern "gib" oder "geben Sie".

          Ups, das sollte natürlich nicht passieren ;-)
          Danke für den Hinweis.

          könnte eine erzwungene Vorschau sehr hilfreich sein

          Die habe ich auch eingebaut, aber vergessen, zu erwähnen.

          Gruß,
          Enrico

        2. [latex]Mae  govannen![/latex]

          Ich habe verstanden, was du willst (glaube ich), aber es ist bei weitem zu kompliziert. Das muss viel einfacher sein, etwa sowas:

          Welches Tier ist grün?

          1. Meerschweinchen
          2. Laubfrosch
          3. Schäferhund
          4. Rabe

          Viel höher würde ich den Schwierigkeitsgrad nicht ansetzen.

          Ich würde sogar auf solch vermeintlich einfache Abfragen eher verzichten. Jemanden, der die deutsche Sprache nur unzureichend/kaum kennt, kann eine solche Frage schon überfordern, da es bei deinem Beispiel bereits um Wörter geht, die außerhalb des üblichen Kommunikations-Deutsch liegen.

          Ich bin bspw. schon an Captchas gescheitert, die ein Firmen-(Logo|Name) zeigen und als Beschreibung "Describe this brand". Natürlich nur amerikanische Firmen, wenn es nicht gerade ein Weltkonzern ist, kennt man die nicht und kann das Captcha nicht lösen.

          Stur lächeln und winken, Männer!
          Kai

          --
          var jQuery = $(hit);
          Wir sind die Schlumpf. Widerschlumpf ist schlumpflos. Wir werden Sie einschlumpfen.
          SelfHTML-Forum-Stylesheet
      3. Hallo,

        bin gerade mit dem Aufbau der Vorschau für in unsere Formulare getätigter Eingaben beschäftigt.

        Ist es sicher, die übergebenen Eingaben in versteckten (type="hidden") und mittels css-Angaben (display:none;height:0px;width:0px) "unsichtbar" gemachten Textfeldern vor dem eigentlichen Absenden zu speichern oder sollte ich hier die übergebenen Eingaben in einem Session-Array ablegen?

        Wie sieht es eigentlich mit der Abänderbarkeit von Parametern aus, die in der Browserzeile stehen?

        Wirken sich hier Eingriffe von Außen auf das letztendliche Abspeichern in einer Textdatei oder Datenbank aus?

        Danke und Gruß,
        Enrico

      4. Hi,

        was ist mit Leuten, die ihre Formulare von ihrem Browser automatisch ausfüllen lassen?
        10 Sekunden dauert das jedenfalls nicht - und wahrscheinlich werden auch die versteckten Formularfelder ausgefüllt. Ich schätze da werden dir einige Euros durch die Lappen gehen ;-)
        Ein einfacher Intelligenztest (1+1=?) dürfte bereits eine effektive Abwehr gegen Spam darstellen.

        Martin