borisbaer: Ist es bei einer POST-Request nötig, den Submit-Button zu prüfen?

Hallo zusammen,

im Zusammenhang mit POST-Requests habe ich schon häufig gesehen, dass zu Beginn überprüft wird, ob die Request vom dafür vorgesehenen Submit-Button initiiert wurde, z.B. so:

if ( isset( $_POST['sign-up'] ) ) {

Ich nehme an, dies geschieht aus Sicherheitsgründen, aber ich habe mich schon oft gefragt, ob das wirklich etwas bringt oder ob es sich hierbei nur um eine weitergetragene Konvention handelt, die eigentlich gar nicht viel nützt.

Könnte mich da jemand aufklären?

Grüße
Boris

  1. if ( isset( $_POST['sign-up'] ) ) {

    Ich nehme an, dies geschieht aus Sicherheitsgründen,

    Naja. Eher zur Vereinfachung. Denn man muss sowieso für jedes erwartete Item prüfen, ob der Schlüssel (Name) vorhanden und das Item mit passenden Daten befüllt wurde.

    Da aber viele Requests von Angreifen oder Testern mit Daten gefüllt werden, die mit dem als Referer vermuteten Formular nichts zu schaffen haben, kann man sich nach der Prüfung auf den Key und Wert des Submit-Buttons in Negativ-Fall den ganzen Rest sparen.

    Vollständig sieht Dein Beispiel grob so aus:

    if ( isset( $_POST['sign-up'] ) ) {
        versuche_daten_zu_verarbeiten();
    } else {
        sende_formular();
    }
    

    Denn gerade bei „Affenformularen“ (das gleiche Skript erzeugt das Formular und verarbeitet die Daten), hat man so eine einfache Möglichkeit, ohne viel Firlefanz die Frage zu entscheiden, ob das Formular gesendet oder mutmaßlich vorhandene andere Daten geprüft oder verarbeitet werden sollen. Das ist regelmäßig der Hauptzweck des von Dir gezeigten Vorgehens.

    Ein weiteter Zweck:

    Ein Formular kann mehrere Submitter haben. Dann muss man für die Auswahl der nachfolgenden Aktionen natürlich prüfen welcher davon mit dem Klick, Tastendruck oder Fingertipp „erfreut“ wurde.

    1. Hallo Raketenwilli,

      mein Minus wegen dem hier.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Lieber Rolf,

        mein Minus wegen dem hier.

        kann $_POST irgendetwas automatisch enthalten, wenn das Formular eben nicht mit POST als Methode versandt wurde? Mir wäre das neu. Deshalb finde ich es völlig in Ordnung, wenn man auf die Prüfung von $_SERVER['REQUEST_METHOD'] verzichtet.

        Liebe Grüße

        Felix Riesterer

        1. Hallo Felix,

          ich nehme alles zurück, inclusive des Minus, und behaupte das Gegenteil.

          Wenn ich ENTER drücke, ist der erste Submit-Button im Request drin, und natürlich kann ich einen Post daran erkennen.

          Weiß nicht, warum ich das mit einem Javascript-Submit verwechselt habe 😟

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Hello,

            ich nehme alles zurück, inclusive des Minus, und behaupte das Gegenteil.

            Wenn ich ENTER drücke, ist der erste Submit-Button im Request drin, und natürlich kann ich einen Post daran erkennen.

            Weiß nicht, warum ich das mit einem Javascript-Submit verwechselt habe 😟

            Ist es nicht so, dass auch ein AJAX-Request eine Methode zu erkennen gibt?

            Oder ist hier good-old-JavaScript jetzt noch etwas anderes als AJAX?

            Glück Auf
            Tom vom Berg

            --
            Es gibt soviel Sonne, nutzen wir sie.
            www.Solar-Harz.de
            S☼nnige Grüße aus dem Oberharz
            1. Hallo TS,

              ja, natürlich. Jeder HTTP Request, ob vom Browser direkt oder über Ajax, hat ein HTTP Verb.

              Ich sprach vom Aufruf der submit-Methode auf dem HTMLFormElement Objekt.

              Rolf

              --
              sumpsi - posui - obstruxi
              1. Hello,

                ja, natürlich. Jeder HTTP Request, ob vom Browser direkt oder über Ajax, hat ein HTTP Verb.

                Ich sprach vom Aufruf der submit-Methode auf dem HTMLFormElement Objekt.

                Du solltest mal eine Runde Joggen gehen und dann heiß/kalt duschen ;-P

                Glück Auf
                Tom vom Berg

                --
                Es gibt soviel Sonne, nutzen wir sie.
                www.Solar-Harz.de
                S☼nnige Grüße aus dem Oberharz
    2. Naja. Eher zur Vereinfachung. Denn man muss sowieso für jedes erwartete Item prüfen, ob der Schlüssel (Name) vorhanden und das Item mit passenden Daten befüllt wurde.

      Das ist mir neu. Oftmals sind POST-Werte doch aber auch leer.

      Da aber viele Requests von Angreifen oder Testern mit Daten gefüllt werden, die mit dem als Referer vermuteten Formular nichts zu schaffen haben, kann man sich nach der Prüfung auf den Key und Wert des Submit-Buttons in Negativ-Fall den ganzen Rest sparen.

      Wieso den Key und den Wert? Ich dachte, ich gebe dem Submit-Button einfach ein Name-Attribut und der Wert dieses Attributs wird bei der POST-Anfrage immer mitgeschickt. Also z.B.

      <button name="sign-in">einloggen</button>
      

      Und dann zu Beginn des Scripts, das durch die POST-Anfrage eingeleitet werden soll, einfach mit isset() prüfen, ob $_POST['sign-up'] vorliegt.

      Vollständig sieht Dein Beispiel grob so aus:

      if ( isset( $_POST['sign-up'] ) ) {
          versuche_daten_zu_verarbeiten();
      } else {
          sende_formular();
      }
      

      Mit sende_formular() meinst du, dass man zurück auf die Seite, auf der sich das Formular befindet, weitergeleitet wird?

      Denn gerade bei „Affenformularen“ (das gleiche Skript erzeugt das Formular und verarbeitet die Daten), hat man so eine einfache Möglichkeit, ohne viel Firlefanz die Frage zu entscheiden, ob das Formular gesendet oder mutmaßlich vorhandene andere Daten geprüft oder verarbeitet werden sollen. Das ist regelmäßig der Hauptzweck des von Dir gezeigten Vorgehens.

      Danke, das ist gut zu wissen.

      Ein weiteter Zweck:

      Ein Formular kann mehrere Submitter haben. Dann muss man für die Auswahl der nachfolgenden Aktionen natürlich prüfen welcher davon mit dem Klick, Tastendruck oder Fingertipp „erfreut“ wurde.

      Ja, in diesem Fall ist es natürlich ohnehin ein Muss. Mir ging es eher um Formulare, die nur einen Submit-Button haben.

      1. Hallo borisbaer,

        Oftmals sind POST-Werte doch aber auch leer.

        Ja. Ein Button mit name, aber ohne value, führt im $_POST Array zu einem Eintrag mit leerem Inhalt. isset() prüft, ob der Eintrag da ist, aber nicht, ob er auch Inhalt hat. Dafür würde man !empty() verwenden.

        <button name="sign-in">einloggen</button>

        Das kann man so machen, vor allem, wenn es nur einen Button gibt. Bei zwei Buttons kann man entweder verschiedene Namen wählen oder einen Namen mit verschiedenen value-Attributen.

        Ob man Script-Kiddies damit scheitern lassen kann, einem Button außer einem name auch einen value zu geben? Ich weiß es nicht. Bei einem <input type="submit"> muss man ja einen Value haben, weil das der einzige Weg ist, dem Button einen Text zu geben. Beim <button> Element ist das nicht nötig, da werden value und Text getrennt gesetzt.

        Mit sende_formular() meinst du, dass man zurück auf die Seite, auf der sich das Formular befindet, weitergeleitet wird?

        So, wie RW das geschrieben hat, ist sende_formular() der GET Zweig. Affenformulare verwenden ja für GET und POST die gleiche URL, deswegen muss das PHP Script erkennen, für welches Verb es verwendet wird. Weswegen es ja auch meine Empfehlung ist, $_SERVER['REQUEST_METHOD'] dafür abzufragen. Der Grund ist: Wenn ich wissen will, ob ich einen POST bekomme, dann prüfe ich das, und nicht etwas anderes, aus dem sich indirekt ergibt, dass ein POST vorliegt.

        Denn letztlich interessiert Dich ja gar nicht, ob sign-in gesetzt ist. Dich interessiert:

        • Wurde gepostet
        • Sind die Formularfelder ausgefüllt

        Ob die Abfrage, ob der Name des Submit-Buttons mitgeschickt wurde, zusätzliche Sicherheit bietet? Höchstens dann, wenn man damit vermeiden kann, dass xy.php seine Daten irrtümlich auf yz.php POSTet. Wenn jemand bösartig ist, dann ist diese Abfrage kein Hinternis.

        Just my 0,0391 Pfennige

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hello,

          Oftmals sind POST-Werte doch aber auch leer.

          Ja. Ein Button mit name, aber ohne value, führt im $_POST Array zu einem Eintrag mit leerem Inhalt. isset() prüft, ob der Eintrag da ist, aber nicht, ob er auch Inhalt hat. Dafür würde man !empty() verwenden.

          Nein.

          Das würde man tunlichst nicht ohne nachzudenken verwenden.
          Denn wenn im Parameter 0, " ", oder "0" drinstehen würde, würde empty() trotzdem TRUE sein, wobei eigentlich nur "0" per HTTP übertragen werden kann. In der lokalen Variable könnten aber trotzdem alle drei Werte vorkommen.

          Daher schrieb ich auch, dass diese Funktion eine Fehlkonstruktion ist.

          Man würde stattdessen strlen() benutzen.

          Liebe Grüße

          Tom vom Berg

          Edit Rolf B: Einen Zeilenumbruch hinzugefügt, weil bei mir das " " auf 2 Zeilen verteilt wurde und damit rätselhaft aussah.

          --
          Es gibt soviel Sonne, nutzen wir sie.
          www.Solar-Harz.de
          S☼nnige Grüße aus dem Oberharz
          1. Das würde man tunlichst nicht ohne nachzudenken verwenden.
            Denn wenn im Parameter 0, " ", oder "0" drinstehen würde, würde empty() trotzdem TRUE sein, wobei eigentlich nur "0" per HTTP übertragen werden kann. In der lokalen Variable könnten aber trotzdem alle drei Werte vorkommen.

            Daher schrieb ich auch, dass diese Funktion eine Fehlkonstruktion ist.

            Man würde stattdessen strlen() benutzen.

            Stimmt, das kam mir nicht in den Sinn. Danke für den Hinweis!

        2. Hallo Rolf,

          Das kann man so machen, vor allem, wenn es nur einen Button gibt. Bei zwei Buttons kann man entweder verschiedene Namen wählen oder einen Namen mit verschiedenen value-Attributen.

          so weit, so klar.

          Ob man Script-Kiddies damit scheitern lassen kann, einem Button außer einem name auch einen value zu geben? Ich weiß es nicht. Bei einem <input type="submit"> muss man ja einen Value haben, weil das der einzige Weg ist, dem Button einen Text zu geben. Beim <button> Element ist das nicht nötig, da werden value und Text getrennt gesetzt.

          Das wäre die Frage.

          So, wie RW das geschrieben hat, ist sende_formular() der GET Zweig.

          Ach so. Beim SignUpController habe ich keinen GET-Zweig. Bei meinem Framework müsste ich ohnehin explizit einen GET-Zweig für den Router „mappen“.
          Mein SignUpController hat nur einen POST-Zweig.

          Affenformulare verwenden ja für GET und POST die gleiche URL, deswegen muss das PHP Script erkennen, für welches Verb es verwendet wird. Weswegen es ja auch meine Empfehlung ist, $_SERVER['REQUEST_METHOD'] dafür abzufragen. Der Grund ist: Wenn ich wissen will, ob ich einen POST bekomme, dann prüfe ich das, und nicht etwas anderes, aus dem sich indirekt ergibt, dass ein POST vorliegt.

          Das ist also die Definition eines Affenformulars. Jetzt habe ich es verstanden. Die Request-Method wird bei mir ohnehin über die Router-Klasse abgefragt. Die Klasse beginnt so:

          #[ Route( path: 'sign-up', method: 'POST' ) ]
          
          public function store(): never
          
          { ...
          

          Denn letztlich interessiert Dich ja gar nicht, ob sign-in gesetzt ist. Dich interessiert:

          • Wurde gepostet
          • Sind die Formularfelder ausgefüllt

          Ja, genau. Das dachte ich mir eben auch, weshalb sich mir dann die Frage stellte, ob ich diese Abfrage bezüglich des entsprechenden Submits nicht auch weglassen könnte.

          Ob die Abfrage, ob der Name des Submit-Buttons mitgeschickt wurde, zusätzliche Sicherheit bietet? Höchstens dann, wenn man damit vermeiden kann, dass xy.php seine Daten irrtümlich auf yz.php POSTet. Wenn jemand bösartig ist, dann ist diese Abfrage kein Hinternis.

          Kein Hindernis, okay, das ist schon mal gut zu wissen. Also kann man sie bei einem einzigen Submit-Button auch getrost weglassen, oder?

          Grüße
          b0r15b43r

        3. Lieber Rolf,

          Ob man Script-Kiddies damit scheitern lassen kann, einem Button außer einem name auch einen value zu geben?

          eine Möglichkeit zur Vermeidung von XSS-Attacken: aus diesen beiden eine Art Schlüssel und Schloss machen. In einer Session legt man fest, welcher Wert im name- und welcher im value-Attribut stehen muss. Ansonsten wird der Request nicht akzeptiert und das Formular macht den Affen.

          Denn letztlich interessiert Dich ja gar nicht, ob sign-in gesetzt ist. Dich interessiert:

          • Wurde gepostet
          • Sind die Formularfelder ausgefüllt

          In meinen Projekten mache ich es mir einfacher:

          • Button übermittelt (Attribut-Wert des name-Attributs als Schlüssel in $_POST vorhanden)?
          • benötigte Daten erhalten (benötigte Schlüssel in $_POST vorhanden)?

          In aller Regel verwende ich den Button dafür, dass das Script später weiß, was es zu tun hat. Dabei ist es dann egal, ob das Formular nur diesen einen Button hat, oder ob es mehrere gibt, die für unterschiedliche Aktionen gedacht sind.

          Was übersehe ich hier, das fürchterlich schiefgehen könnte?

          Just my 0,0391 Pfennige

          Hihihi, Du hast also auch noch Zeiten erlebt, in denen man mit DM bezahlt hat.

          Liebe Grüße

          Felix Riesterer

          1. Hallo Felix,

            Hihihi, Du hast also auch noch Zeiten erlebt, in denen man mit DM bezahlt hat.

            Hat das nicht jeder im Selfhtml-Verein? Außer Janosch vielleicht…

            Rolf

            --
            sumpsi - posui - obstruxi
          2. Guten Abend,

            Just my 0,0391 Pfennige

            Hihihi, Du hast also auch noch Zeiten erlebt, in denen man mit DM bezahlt hat.

            ja, aber Rolf hat sich um zwei Stellen vertan. 🤪

            Einen schönen Tag noch
             Martin

            --
            Im Englischen hat eine Katze neun Leben. Im Deutschen vielleicht auch, aber nach Abzug der Steuern bleiben nur noch sieben übrig.
            1. Hallo Martin,

              meine gefühlte Inflation sagt, dass ich für das, was heute 2ct kosten würde, damals™️ 0,0391 Pfennige bezahlt hätte.

              (Jajaja, ich weiß, die Inflation seit 2002 beträgt nicht 10000%. Laut finanz-tools.de ist der Verbraucherpreisindex von 77 in 2001 auf 115,9 in 2023 gestiegen, das wären 50% Inflation. Allein 16% in den letzten 3 Jahren.)

              Rolf

              --
              sumpsi - posui - obstruxi
  2. Hello,

    Kurzantwort als rhetorische Frage:

    Wie willst Du den Inhalt einer Variable (hier eines Parameters) prüfen, wenn Du nicht weißt, ob sie/er tatsächlich vorhanden ist?

    Der Zugriff auf das Nichts verursacht je nach Programmiersprache lustige Effekte. Bei PHP würde mindestens eine Notice ausgelöst werden und NULLoder FALSEzurückgeliefert werden.

    Das hat dann aber nichts mehr mit dem Inhalt des Posts zu tun.

    Isset() soll genau dies verhindern! Und empty() ist aufgrund der automatiachen Typkonvertrierung mMn eine Fehlkonstruktion! Das sollte wieder entfernt werden aus dem Funktionsumfang.

    im Zusammenhang mit POST-Requests habe ich schon häufig gesehen, dass zu Beginn überprüft wird, ob die Request vom dafür vorgesehenen Submit-Button initiiert wurde, z.B. so:

    if ( isset( $_POST['sign-up'] ) ) {

    Ich nehme an, dies geschieht aus Sicherheitsgründen, aber ich habe mich schon oft gefragt, ob das wirklich etwas bringt oder ob es sich hierbei nur um eine weitergetragene Konvention handelt, die eigentlich gar nicht viel nützt.

    Könnte mich da jemand aufklären?

    Grüße
    Boris

    Glück Auf
    Tom vom Berg

    --
    Es gibt soviel Sonne, nutzen wir sie.
    www.Solar-Harz.de
    S☼nnige Grüße aus dem Oberharz
    1. Hallo Tom,

      wie lange machst Du schon PHP?

      Bei PHP würde mindestens eine Notice ausgelöst werden und NULL oder FALSE zurückgeliefert werden.

      Ja, die Abfrage if ($_POST['foo']) würde bei Abwesenheit des POST-Parameters "foo" eine Notice auslösen.

      Wie willst Du den Inhalt einer Variable (hier eines Parameters) prüfen, wenn Du nicht weißt, ob sie/er tatsächlich vorhanden ist?

      isset und empty sind keine Funktionen, sondern Sprachkonstrukte, und unterdrücken die Notice. Dafür sind sie da.

      Andernfalls müsste man mit array_key_exists($_POST, 'foo') herumhantieren.

      TIL: isset unterstützt mehr als einen Parameter und liefert nur true, wenn alle gesetzt sind.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Hello Rolf,

        wenn Du hier das MINUS vergeben hast, denk nochmal genau darüber nach!

        Wenn ich als Designer des HTML-Dokuments bestimme, dass eine Antwort nur mittels Post und Button stattfinden soll, dann darf ich das im Request auch erwarten. Sonst macht der Vorgang eben nochmal den Affen...

        wie lange machst Du schon PHP?

        Länger als Du, und ich halte mich im Gegensatz zu Dir auch nicht für unfehlbar!

        Bei PHP würde mindestens eine Notice ausgelöst werden und NULL oder FALSE zurückgeliefert werden.

        Ja, die Abfrage if ($_POST['foo']) würde bei Abwesenheit des POST-Parameters "foo" eine Notice auslösen.

        Wie willst Du den Inhalt einer Variable (hier eines Parameters) prüfen, wenn Du nicht weißt, ob sie/er tatsächlich vorhanden ist?

        isset und empty sind keine Funktionen, sondern Sprachkonstrukte, und unterdrücken die Notice. Dafür sind sie da.

        Andernfalls müsste man mit array_key_exists($_POST, 'foo') herumhantieren.

        TIL: isset unterstützt mehr als einen Parameter und liefert nur true, wenn alle gesetzt sind.

        Rolf

        Glück Auf
        Tom vom Berg

        --
        Es gibt soviel Sonne, nutzen wir sie.
        www.Solar-Harz.de
        S☼nnige Grüße aus dem Oberharz
        1. Hallo TS,

          Wenn ich als Designer des HTML-Dokuments bestimme, dass eine Antwort nur mittels Post und Button stattfinden soll, dann darf ich das im Request auch erwarten.

          Ja. Keine Einwände.

          Darum ging es hier aber nicht. Sondern darum, dass Du - zumindest schien es mir so - durch diesen Satz

          Wie willst Du den Inhalt einer Variable (hier eines Parameters) prüfen, wenn Du nicht weißt, ob sie/er tatsächlich vorhanden ist?

          die Sinnhaftigkeit der isset-Abfrage grundsätzlich bestritten hast.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Hello,

            Wenn ich als Designer des HTML-Dokuments bestimme, dass eine Antwort nur mittels Post und Button stattfinden soll, dann darf ich das im Request auch erwarten.

            Ja. Keine Einwände.

            Darum ging es hier aber nicht. Sondern darum, dass Du - zumindest schien es mir so - durch diesen Satz

            Wie willst Du den Inhalt einer Variable (hier eines Parameters) prüfen, wenn Du nicht weißt, ob sie/er tatsächlich vorhanden ist?

            die Sinnhaftigkeit der isset-Abfrage grundsätzlich bestritten hast.

            Eher das Gegenteil, oder?

            Der Sinn von isset() ist doch gerade, ohne Notice rechtzeitig festzustellen, ob ein Parameter/eine Variable bereits vorhanden ist, bevor ich unkoordiniert darauf zugreife!

            Hast Du heute schon 'was geraucht? ;-P

            Glück Auf
            Tom vom Berg

            --
            Es gibt soviel Sonne, nutzen wir sie.
            www.Solar-Harz.de
            S☼nnige Grüße aus dem Oberharz
            1. Hallo TS,

              die Locales de-rolf und de-tom scheinen inkompatibel zu sein.

              Hast Du heute schon 'was geraucht? ;-P

              Ja. Bestes Gras.

              Möglicherweise hab ich das Falsche dazu getrunken.

              Rolf

              --
              sumpsi - posui - obstruxi
  3. Hallo borisbaer,

    einen POST erkennt man an $_SERVER['REQUEST_METHOD'] == "POST".

    Die Abfrage auf einen konkreten Submit-Button kann man nachgelagert ausführen, falls es mehr als einen davon gibt.

    Aber nur dann. Es gibt keine Garantie, dass Du den value eines Submit-Buttons in $_POST findest. Ein Submit per ENTER Taste oder per JavaScript form.submit() setzt keinen Submit-Button in den Request.

    Update: Ein Hirnfurz meinerseits. Die ENTER Taste schickt natürlich den ersten Submit-Button im Form mit. Insofern kann man natürlich den POST durch Abfrage der Existenz des Submit-Button-Namens im $_POST prüfen, solange clientseitig kein submit mittels JavaScript erfolgt.

    Rolf

    --
    sumpsi - posui - obstruxi
  4. Hello Boris,

    im Zusammenhang mit POST-Requests habe ich schon häufig gesehen, dass zu Beginn überprüft wird, ob die Request vom dafür vorgesehenen Submit-Button initiiert wurde, z.B. so:

    if ( isset( $_POST['sign-up'] ) ) {

    Als Ergänzung zu den ganzen Ausführungen im Thread:

    Der Submit-Button ist meistens der Selektor für den Router im Backend. Es gibt also oft mehrere davon, die dann die gewünschte Aktion auswählen.

    Es darf aber nur einer der Buttons (oder keiner) im Request übertragen werden. Sonst liegt eine Manipulation vor. Es gab dazu vor einiger Zeit (12.03.2023) hier schon einen Thread, in dem wir das untersucht haben.

    Die Frage kam auch von Dir!

    Sammele die Erkenntnisse bitte mal und werte sie aus. Vielleicht kannst Du es dann sogar so gut zusammenfassen, dass daraus ein kleiner Artikel fürs Wiki zum Thema "Programmlogik" wird?

    Glück Auf
    Tom vom Berg

    --
    Es gibt soviel Sonne, nutzen wir sie.
    www.Solar-Harz.de
    S☼nnige Grüße aus dem Oberharz