Manuel: $_POST Variable auf Validität überprüfen

Guten Abend,

Ich schicke Inhalte mittels eines FormDatas vom Client an den Server; - diese landen dann ja in der globalen $_POST Variable.

Bevor ich deren Inhalt nun sanitize, muss ich irgendwie vorher überprüfen, ob der Client Input überhaupt valide ist?

So in die Richtung

// DUMMYCODE

if (gettype($_POST) !== string && gettype($_POST) !== formData /* ok, zweiter Teil funktioniert so natürlich nicht, nur exemplarisch veranschaulicht... */)

Frage also nochmal kurz gefasst:

Wie überprüfe ich, ob der $_POST Variable überhaupt korrekte Werte aus einer korrekten Herkunft (formData) übergeben werden?

Schöne Grüße, Manuel

  1. Hallo,

    Ich schicke Inhalte mittels eines FormDatas vom Client an den Server; - diese landen dann ja in der globalen $_POST Variable.

    Bevor ich deren Inhalt nun sanitize, muss ich irgendwie vorher überprüfen, ob der Client Input überhaupt valide ist?

    was bezeichnest du in diesem Fall als valide?

    // DUMMYCODE
    
    if (gettype($_POST) !== string && gettype($_POST) !== formData /* ok, zweiter Teil funktioniert so natürlich nicht, nur exemplarisch veranschaulicht... */)
    

    PHP selbst garantiert dir, dass $_POST immer vom Typ Array ist, und dessen einzelne Elemente vom Typ String. Und wenn die POST-Daten in der für Formulare üblichen Notation key1=value1&key2=value2 ankommen, hast du diese Key/Value-Pärchen nachher sauber im $_POST-Array. Was willst du da also weiter überprüfen?

    Wie überprüfe ich, ob der $_POST Variable überhaupt korrekte Werte aus einer korrekten Herkunft (formData) übergeben werden?

    Die Herkunft kannst du nicht überprüfen. Du kannst und solltest nur überprüfen,

    • ob $_POST die Keys enthält, die du erwartest
    • und ob deren Werte "gültig sind", also deinen Erwartungen entsprechen.
    • Optional: Prüfen, ob es weitere Nonsense-Keys gibt, die gar nicht ins Konzept passen. Normalerweise würde man die einfach ignorieren, man könnte aber auch den ganzen Request abweisen.

    Einen schönen Tag noch
     Martin

    --
    Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
    1. Du:

      PHP selbst garantiert dir, dass $_POST immer vom Typ Array ist, und dessen einzelne Elemente vom Typ String.

      Rolf:

      dass $_POST ein Array ist (ein String ist es nie), brauchst du nicht zu prüfen. Dass ein Eintrag in $_POST ein String ist, auch nicht.

      Test:

      <html>
      <form
      method="post"
      action="https://home.fastix.org/phpinfo.php#_POST">
      <input name="foo[0]" value="bar_0">
      <input name="foo[1]" value="bar_1">
      <button>Weg damit!</button>
      </form>
      </html>
      

      Die Auswertung ergibt dann:

      $_POST['foo'][0]='bar_0';
      $_POST['foo'][1]='bar_1';
      

      $_POST['foo'] ist damit ganz klar ein Array, kein String.

      Das lässt sich übrigens auch weiter treiben:

      <input name="foo[0][tok]" value="bar_0">
      <input name="foo[1][tok]" value="bar_1">
      

      Ergebnis:

      $_POST['foo'][0]['tok']='bar_0';
      $_POST['foo'][1]['tok']='bar_1';
      

      Grüße aus Ganzgenauheim.

      1. Hallo,

        <html>
        <form
        method="post"
        action="https://home.fastix.org/phpinfo.php#_POST">
        <input name="foo[0]" value="bar_0">
        <input name="foo[1]" value="bar_1">
        <button>Weg damit!</button>
        </form>
        </html>
        

        $_POST['foo'] ist damit ganz klar ein Array, kein String.

        Erbsenzähler. 😉

        Ja, stimmt: PHP scheint intern stumpf eine Zuweisung der Form

        $_POST[key] = value;
        

        auszuführen. Deshalb ergibt sich als Bestandteil von $_POST auch wieder ein Array, wenn der key bereits eckige Klammern enthält und so einen syntaktisch korrekten PHP-Arrayausdruck darstellt.
        Die eckigen Klammern dürfen dabei auch leer sein, dann vergibt PHP den Index selbst (numerisch von 0 beginnend).

        Das ist ein Feature, das man vor allem bei der Verarbeitung von Checkboxen gern nutzt.

        Einen schönen Tag noch
         Martin

        --
        Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
        1. Erbsenzähler. 😉

          Versuche mal einen Bürger aus Ganzgenauheim dazu zu bewegen, einen Erbseneintopf zu essen, wenn die Zahl der Erbsen und Speckbrocken in der stets beizulegenden Akte nicht richtig angegeben wurde. Man könnte meinen, das wären alles Programmier-Fuzzies.

        2. Hallo Martin,

          Erbsenzähler. 😉

          Ziemlich eckige Erbsen []

          Dass wir beide nicht an Array-Posts gedacht haben, ist schon ärgerlich.

          Immerhin kommt das für's Programm nicht überraschend - wenn ich ein Form mit Namen baue, die eckige Klammern enthalten, dann weiß ich das beim Entgegennehmen. Oder sollte es zumindest wissen…

          Rolf

          --
          sumpsi - posui - obstruxi
    2. Die Herkunft kannst du nicht überprüfen. Du kannst und solltest nur überprüfen,

      • ob $_POST die Keys enthält, die du erwartest
      • und ob deren Werte "gültig sind", also deinen Erwartungen entsprechen.
      • Optional: Prüfen, ob es weitere Nonsense-Keys gibt, die gar nicht ins Konzept passen.

      So „optional“ ist die letzte Prüfung gar nicht. Insbesondere bei Nutzung externer, scheinbar gut dokumentierter und oft genutzer Libarys (oder meinetwegen Wordpress-Plugins) könnte ein Angreifer ungewollte / nicht erwartete Key:Value-Paare einschmuggeln, auf welche die Libs dann in einer „nicht dokumentierten Weise“ reagieren - und plötzlich hat ein Angreifer dadurch ungeahnte Möglichkeiten…

      Außerdem kann man so Nessus-Benutzer & Co (warum macht das wohl jemand, den man nicht aufgefordert hat) auch ausbremsen.

      Da das gleiche Problem auch andere Variablen betreffen kann (e.g. $_GET, $_COOKIE, $_REQUEST, Daten von API-Schleudern...) habe ich mal fix eine Funktion hierfür entworfen.

      Freilich kann, darf und muss man diese für feinere Prüfungen anpassen…, kann z.B. einfach false zurückgeben und also außerhalb der Funktion reagieren.

      <?php
      error_reporting( E_ALL );
      ini_set( 'display_errors', 1 );
      
      /**
       * Function: simpleArrayCheck
       * will stop the skript if the array ist not complete or maybe tainted.
      
       * Params:
       * 1: One array with awaited keys.
       * 2: The suspected array.  
       * 3: Show for unexpexted keys (Array is tainted)?
       *    boolean, Default: true
       * 4: The name for the array in error-messages 
       *    string , Default: 'Array'
       * Return: true or die with error-message
      */
      
      
      function simpleArrayCheck(
      	$awaitedKeys,
      	$arr,
      	$strong = true,
      	$arrName = 'Array'
      ) {
      	# Has all keys?
      
      	foreach ( $awaitedKeys as $key ) {
      		if ( !  array_key_exists( $key, $arr )  ) {
      			http_response_code( 400 );
      			trigger_error( 
      				'Key "' . $key . '" is not ' . $arrName . '.',
      				E_USER_ERROR
      			);
      		}
      	}
      
      	# Maybe taintet?
          if ( $strong )  {
      		foreach ( array_keys( $arr ) as $key ) {
      			if ( ! in_array ( $key, $awaitedKeys ) ) {
      				http_response_code( 400 );
      				trigger_error(
      					'Unknown Key "' . $key . '" in Array "' . $arrName . '". Attack?',
      					E_USER_ERROR
      				);
      			}
      		}
      	}
      	
      	return true;
      }
      
      /** 
       * Tests
      */
      
      
      $awaitedKeys = [
      	'foo',
      	'bar',
      	'baz'
      ];
      
      
      /*
      ### Fine:
      $_POST['foo'] = 'Hallo1';
      $_POST['bar'][] = 'Hallo2';
      $_POST['bar'][] = 'Hallo3';
      $_POST['baz'][] = 'Hallo4';
      $_POST['baz'][] = 'Hallo5';
      if ( simpleArrayCheck( $awaitedKeys, $_POST, true, '$_POST' ) ) {
          echo "fine." . PHP_EOL;
      }
      #*/
      
      /*
      ### Key fehlt:
      $_POST['foo'] = 'Hallo1';
      simpleArrayCheck( $awaitedKeys, $_POST, true, '$_POST' );
      #*/
      
      /*
      ### Nicht erwarteter Key
      $_POST['foo'] = 'Hallo1';
      $_POST['bar'][] = 'Hallo2';
      $_POST['bar'][] = 'Hallo3';
      $_POST['baz'][] = 'Hallo4';
      $_POST['baz'][] = 'Hallo5';
      $_POST['tok'][] = 'Hallo5';
      
      if  ( simpleArrayCheck( $awaitedKeys, $_POST, false, '$_POST' ) ) {
      	echo "Not strong? fine!" . PHP_EOL;
      }
      simpleArrayCheck( $awaitedKeys, $_POST, true, '$_POST' );
      #*/
      
    3. Hallo,

      Wie überprüfe ich, ob der $_POST Variable überhaupt korrekte Werte aus einer korrekten Herkunft (formData) übergeben werden?

      Die Herkunft kannst du nicht überprüfen.

      hier sei das Stichwort Cross-Site-Request-Forgery/CSRF erwähnt und eine Gegenmaßnahme (Einführung und Überprüfung eines CSRF-Tokens). Kein 100%-Schutz wohlgemerkt.

      Viele Grüße Matti

      1. Hallo,

        Wie überprüfe ich, ob der $_POST Variable überhaupt korrekte Werte aus einer korrekten Herkunft (formData) übergeben werden?

        Die Herkunft kannst du nicht überprüfen.

        hier sei das Stichwort Cross-Site-Request-Forgery/CSRF erwähnt

        Ich glaube wegen des Sachbezugs „$_POST Variable auf Validität überprüfen“, dass Martin mit „Herkunft“ meinte, ob die Daten tatsächlich aus einem Formular und damit von einem Browser kommen - oder ob diese etwa mit anderer Software (wget, curl, …) generiert und verschickt wurden.

        Tatsächlich kann man das (mit diversen Krücken, welche sich manchmal als Zugangsverhinderer herausstellen) nur erschweren, nicht wirklich verhindern. Denn schließlich wurden diese Werkzeuge ja geschaffen, um das Verhalten der Browser zu simulieren.

        1. Hi,

          Wie überprüfe ich, ob der $_POST Variable überhaupt korrekte Werte aus einer korrekten Herkunft (formData) übergeben werden?

          Die Herkunft kannst du nicht überprüfen.

          hier sei das Stichwort Cross-Site-Request-Forgery/CSRF erwähnt

          Ich glaube wegen des Sachbezugs „$_POST Variable auf Validität überprüfen“, dass Martin mit „Herkunft“ meinte, ob die Daten tatsächlich aus einem Formular und damit von einem Browser kommen - oder ob diese etwa mit anderer Software (wget, curl, …) generiert und verschickt wurden.

          genau das meinte er, und genau an diese Tools hatte er auch gedacht. 😉

          Einen schönen Tag noch
           Martin

          --
          Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
          1. genau das meinte er, und genau an diese Tools hatte er auch gedacht. 😉

            Klar. Aber jetzt weißt Du „aus der Bestätigung eines Dritten“, dass das einem (Sorry: Es folgt noch mehr „Juristen-Deutsch“:) „hinreichend aufmerksamen und verständigem Leser“ (als der ich hoffentlich gelten kann) „durchaus erkannt werden konnte“. „Mithin“ also, dass Du korrekt formuliert hast. 😉

        2. Hallo,

          Die Herkunft kannst du nicht überprüfen.

          hier sei das Stichwort Cross-Site-Request-Forgery/CSRF erwähnt

          Ich glaube wegen des Sachbezugs „$_POST Variable auf Validität überprüfen“, dass Martin mit „Herkunft“ meinte, ob die Daten tatsächlich aus einem Formular und damit von einem Browser kommen - oder ob diese etwa mit anderer Software (wget, curl, …) generiert und verschickt wurden.

          Tatsächlich kann man das (mit diversen Krücken, welche sich manchmal als Zugangsverhinderer herausstellen) nur erschweren, nicht wirklich verhindern. Denn schließlich wurden diese Werkzeuge ja geschaffen, um das Verhalten der Browser zu simulieren.

          Ich hatte das auch genau so verstanden - aber CSRF-Tokens sind ja genau ein einfaches Stilmittel, um die primitivsten "Angriffsversuche"[1] durch curl/wget zu unterbinden. Das man damit bessere Bots (WebDriver) nicht findet ist klar.

          Viele Grüße Matti

          [1] Also Absendung eines Requests ohne Browser/Formular

          1. um die primitivsten "Angriffsversuche"[1] durch curl/wget zu unterbinden. Das man damit bessere Bots (WebDriver) nicht findet ist klar.

            Ich glaube fast, Du musst die Manuals zu wget und curl nochmal lesen.

            WebDriver (von Selenium) ist dann auch nur ein „Frontend“, welches einen Browser (offenbar headless) steuert und dabei Benutzeraktionen simuliert - wofür der Browser aber eine API bereitstellen muss. Deshalb ist das quelloffene Chrome dessen natives Werkzeug. Aber simulieren/scripten lässt sich das auch auch mit wget oder curl. Jedenfalls beherrschen beide das gesamte HTTP-Protokoll.

            1. Hallo,

              was soll das denn jetzt? Deine Nachricht liest sich sehr herablassend, vor allem, da du wesentliche Satzteile unterschlägst.

              Dass ich insb. mit curl so ziemlich alles an HTTP-Requests nachbauen kann ist klar - insbesondere kann ich ein Formular abholen, es parsen, ein CSRF-Token extrahieren und dann mit Curl einen neuen Request senden mit den Formulardaten inkl. des CSRF-Tokens.

              Das wichtige war aber nicht wget/curl, sondern "primitivste Angriffsversuche mit curl/wget" - sprich: wenn man den ersten Schritt (CSRF-Token holen/extrahieren) eben nicht macht, sondern nur einen direkten Request auf den "Speicherendpunkt". Die (beispielhaft) genannte WebDriver-API würde solche primitiven Request-Versuche btw ebenfalls zulassen, ist also alleine nicht ausreichend, um CSRF-Schutz auszuhebeln.

              Mit CSRF-Tokens kann man primitive Versuche erkennen, bei denen das Formular eben nicht mit Browser gesandt wird. Andere Möglichkeiten sind z.B. Captchas und ähnliche Spielereien, aber es gibt keinen 100% Schutz dagegen, dass eine Webseite gescraped wird bzw. Formularendpunkte automatisiert aufgerufen werden.

              Andersherum: das Vorhandensein eines gültigen CSRF-Tokens ist eine notwendige, aber eben nicht hinreichende Bedingung dafür, dass die "Herkunft" des Requests ein user-genutzter Web-Browser (Browser i.S.v.: manuell genutzt) ist.

              Und das war alles was ich sagen wollte.

              Viele Grüße Matti

  2. Hallo Manuel,

    dass $_POST ein Array ist (ein String ist es nie), brauchst du nicht zu prüfen. Dass ein Eintrag in $_POST ein String ist, auch nicht.

    Prüfen musst du:

    Bevor du in die POST Verarbeitung einsteigst: hat der Client einen POST Request geschickt (über $_SERVER['REQUEST_METHOD'])

    Bevor du $_POST['foo'] ausliest: hat der Client dafür einen Wert geschickt. Denn sonst schreibt PHP eine Notice wegen Zugriffs auf ein nicht existierendes Arrayelement. Dafür gibt's mehrere Wege:

    • isset($_POST['foo']) liefert true, wenn ein Wert geschickt wurde
    • empty($_POST['foo']) liefert false, wenn kein Wert geschickt wurde oder wenn er leer ist
    • die filter... Funktionen verwenden, soweit ich weiß, Defaultwerte ("" oder 0), wenn kein Wert geschickt wurde
    • einen Defaultwert kannst du auch mit dem null coalescing Operator ?? erzeugen:

    $foo = $_POST['foo'] ?? 'Bar';

    Damit kannst du dann in Plausis und Sanitizing einsteigen.

    Rolf

    --
    sumpsi - posui - obstruxi
  3. Lieber Manuel,

    vielleicht hilft es in Deinem Fall, eine Erwartung an die Daten zu formulieren?

    Liebe Grüße

    Felix Riesterer

    1. Ok, jede Menge Stoff. :)

      Werden die KEY -> VALUE Paarungen eines $_POST Arrays dabei intrinsisch automatisch als STRING -> STRING interpretiert oder kann das alles mögliche sein (z.B. VAR -> BOOL, NUMBER -> NUMBER etc.)? ...bzw. existieren bezüglich des Typs Einschränkungen, z.B. Typus Variable nicht erlaubt...?

      Danke, Manuel

      1. Hallo,

        Ok, jede Menge Stoff. :)

        ja, niemand hat gesagt, das wäre einfach. 🧑‍🔬

        Werden die KEY -> VALUE Paarungen eines $_POST Arrays dabei intrinsisch automatisch als STRING -> STRING interpretiert

        Aufgepasst! PHP ist eine schwach typisierte Sprache. Das heißt, PHP kennt und unterscheidet zwar verschiedene Datentypen, konvertiert aber je nach Kontext lustig hin und her, meist ohne dass man es merkt. Deswegen ist dein Begriff "interpretiert" hier mit Vorsicht zu genießen.
        Interpretiert werden die Parameter als der Typ, der in einem bestimmten Ausdruck erforderlich ist. Steht also z.B. ein URL-Parameter in einem arithmetischen Ausdruck, wird er automatisch von String zu Number konvertiert - mit der Nebenwirkung, dass unerwartete Ergebnisse auftreten können, wenn der String etwas enthält, was nicht in einen Zahlenwert umgewandelt werden kann. So wird etwa der String "123.45" wie erwartet in die Zahl 123.45 konvertiert, der String "123,45" aber in die Zahl 123 (Achtung, Komma anstatt Dezimalpunkt!). Und der String "foo" wird einfach zu 0.

        Angeliefert werden die Werte aber alle zunächst als String. Das ist auch logisch, denn sie werden ja aus den URL-Parametern gebildert, und die werden nun einmal als String im Request übermittelt. Eine weitergehende Interpretation oder Umwandlung findet nicht statt, wenn diese Werte in $_POST an das Script durchgereicht werden.

        Davon unabhängig gilt, was Rolf und ich zunächst beide nicht bedacht haben: Haben die Keys bereits eckige Klammern (Array-Syntax), dann baut PHP daraus tatsächlich ein Array.

        oder kann das alles mögliche sein (z.B. VAR -> BOOL, NUMBER -> NUMBER etc.)?

        Nein. Du kannst die Werte nachher in deinem Script so interpretieren, wenn es dein Programmkontext so vorsieht. Aber original in $_POST sind es Strings.

        Einen schönen Tag noch
         Martin

        --
        Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
        1. Hallo

          Angeliefert werden die Werte aber alle zunächst als String. Das ist auch logisch, denn sie werden ja aus den URL-Parametern gebildert, und die werden nun einmal als String im Request übermittelt.

          Möchtest du das noch einmal neu formulieren? Seit wann werden POST-Daten in der URL übermittelt? Ist dir gedanklich etwa die Methode GET dazwischengerutscht?

          Tschö, Auge

          --
          200 ist das neue 35.
          1. Hi,

            Angeliefert werden die Werte aber alle zunächst als String. Das ist auch logisch, denn sie werden ja aus den URL-Parametern gebildert, und die werden nun einmal als String im Request übermittelt.

            Möchtest du das noch einmal neu formulieren? Seit wann werden POST-Daten in der URL übermittelt?

            werden sie nicht, sondern im Request Body. Aber meines Wissens werden sie trotzdem als URL-Parameter bezeichnet.
            Deshalb schrieb ich im letzten Halbsatz bewusst allgemein im Request.

            Ist dir gedanklich etwa die Methode GET dazwischengerutscht?

            Naja, was heißt reingerutscht ... Ich wollte eine allgemeine Formulierung, die auf beides passt.

            Einen schönen Tag noch
             Martin

            --
            Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
            1. Hallo Martin,

              die allgemeine Bezeichnung ist Request-Parameter. Diese können per URL oder POST Body übermittelt werden.

              Einen POST-Body gibt's natürlich nur bei einem POST-Request (also method="POST" im Form oder beim Fetch-Aufruf).

              Mangels Testmöglichkeit kann ich gerade nicht sagen, was bei einem PUT Request passiert. Der hat auch einen Body - aber verarbeitet PHP den bei passendem enctype und befüllt das $_POST Array?

              Und ich frage mich: wenn ich einen POST Request an die URL ˋfoo.php?dings=bumsˋ sende (dies also als action-Parameter eines form Elements notiere), finde ich den dings-Parameter dann in $_GET oder $_POST?

              Rolf

              --
              sumpsi - posui - obstruxi
              1. Hallo

                Und ich frage mich: wenn ich einen POST Request an die URL ˋfoo.php?dings=bumsˋ sende (dies also als action-Parameter eines form Elements notiere), finde ich den dings-Parameter dann in $_GET oder $_POST?

                Der Parameter dings sollte im GET-Array zu finden sein. Zumindest, wenn ich ein HTML-Formular per POST sende und im Action-Attribut ein Ziel mitsamt URL-Parameter angebe, landet er genau dort.

                Tschö, Auge

                --
                200 ist das neue 35.
              2. Hallo Rolf,

                die allgemeine Bezeichnung ist Request-Parameter.

                ah, dann meinte ich das eigentlich, danke.

                Mangels Testmöglichkeit kann ich gerade nicht sagen, was bei einem PUT Request passiert.

                Meines Wissens ist PUT in typischen Web-Szenarien kein Thema. Ein Apache beantwortet einen PUT-Request "out of the box" mit Status 405 Method not allowed. Man kann das aber in der Konfiguration freischalten, z.B. für WebDAV, aber dann muss man dem Indianer auch einen passenden Helfer zur Seite stellen, der den Request dann bearbeitet.
                Soweit ich weiß, wird beim PUT ganz ähnlich wie beim POST die Payload (also der zu speichernde Dateiinhalt) im Request Body übermittelt. Dieses mein Wissen ist aber Theorie und da auch nur Stückwerk.

                Der hat auch einen Body - aber verarbeitet PHP den bei passendem enctype und befüllt das $_POST Array?

                Der kommt im Normalfall nie bei PHP an, würde ich mal sagen. Ein bisschen wie bei den Pinguinen und den Eisbären: Die Pinguine brauchen keine Verteidigungsstrategie gegen Eisbären, weil sie sich unter normalen Lebensumständen nie begegnen.

                Und ich frage mich: wenn ich einen POST Request an die URL ˋfoo.php?dings=bumsˋ sende (dies also als action-Parameter eines form Elements notiere), finde ich den dings-Parameter dann in $_GET oder $_POST?

                Wie Auge schon sagte: Diesen einen Parameter bekommst du dann in $_GET, die eigentlichen Formulardaten in $_POST.

                Einen schönen Tag noch
                 Martin

                --
                Ich fürchte, ich brauche ein neues Portemonnaie. Das alte ist leer.
                1. Hallo,

                  Okay, danke für euer aller Einsatz!

                  Ist tatsächlich spannend, die Diskussion mitzuverfolgen.

                  Wenn ich das nur nochmal kurz zusammenfassen darf, nur um sicherzugehen, dass ich das jetzt auch richtig verstanden habe:

                  1. Wenn ich vom Client per FormData Inhalte per method: "post" ans Backend schicke, dann kommen die in der $_POST Variable als STRINGS an.

                  2. Dort reicht daher eine Überprüfung, ob tatsächlich Daten geschickt wurden ( ISSET() ), und ein $braverWert = filter_var($Ursprungswert, FILTER_SANITIZE_SPECIAL_CHARS);

                  Könnte man das ansatzweise so unterschreiben?

                  Danke, Manuel.

                  1. Hallo Manuel,

                    im Grunde genommen ja.

                    Solange Du den Sonderfall im Kopf behältst, dass Du im name-Attribut des HTML ein Array bestellen kannst, also so:

                    <input type="text" name="wert[]">
                    <input type="text" name="wert[]">
                    <input type="text" name="wert[]">
                    

                    (was im real life natürlich durch Labels und Layout zu ergänzen ist)

                    dann bekommst Du in $_POST['wert'] keinen String, sondern ein Array von Strings. Aber dann hast Du das HTML auch hoffentlich absichtlich so geschrieben und weißt, dass ein Array kommt. Diese Schreibweise ist eine Spezialität von PHP, um ein Form mit mehreren gleichartigen Elementen einfacher verarbeiten zu können.

                    Rolf

                    --
                    sumpsi - posui - obstruxi
                    1. Dort reicht daher eine Überprüfung, ob tatsächlich Daten geschickt wurden ( ISSET() ), und ein $braverWert = filter_var($Ursprungswert, FILTER_SANITIZE_SPECIAL_CHARS);

                    Könnte man das ansatzweise so unterschreiben?

                    Nein. Das reicht nämlich „nur vielleicht“.

                    • Dein Job: Definiere „reicht“. Besonders das „Wofür“!
                    • Ich beuge hier mal vor, weil immer wieder mal jemand vorbeikommt und glaubt eine Zaubermethode gefunden zu haben, die „auf alles“ passe: Du kommst nicht darum herum, die Inhalte der Variablen dem Kontext gemäß zu behandeln und da ist es ein Unterschied, ob Du diese Daten in einer Datenbank speichern oder im HTML ausgeben willst - und wenn in HTML, so z.B. als Inhalt normaler Elemente oder als Value von Formularelementen.
                    • Und weil ich nicht Montags bei heise.de als der „Dummkopf der Woche“ erwähnt werden will, der unterschrieben habe, dass das reicht, verweigere ich die Unterschrift - und das sehr wohl begründet.
                  2. Hallo

                    Wenn ich das nur nochmal kurz zusammenfassen darf, nur um sicherzugehen, dass ich das jetzt auch richtig verstanden habe:

                    1. Wenn ich vom Client per FormData Inhalte per method: "post" ans Backend schicke, dann kommen die in der $_POST Variable als STRINGS an.

                    2. Dort reicht daher eine Überprüfung, ob tatsächlich Daten geschickt wurden ( ISSET() ), und ein $braverWert = filter_var($Ursprungswert, FILTER_SANITIZE_SPECIAL_CHARS);

                    Könnte man das ansatzweise so unterschreiben?

                    Nein, nicht einmal ansatzweise könnte man das. Wie du selbst konstatierst, kommt in den per POSt übermittelten Daten alles als String oder Array von Strings an. Das bedeutet auch, dass da prinzipiell aller möglicher Mist drinstehen kann, unabhängig davon, was du als Eingabe vorgesehen hast.

                    Je nach Anwendungsszenario erwartest du als Formularanbieter bestimmte Daten in einem bestimmten Format, wichtiger noch, du willst sie im Zweifelsfall in einem bestimmten Format abspeichern, was speziell in Datenbanken, in denen Feldformate fest vorgegeben sind, in die Hose gehen kann, wenn unerwartete Werte dargeboten werden.

                    Du kommst also üblicherweise nicht um eine Prüfung jedes einzelnen Feldes gemäß deinen Erwartungen herum.

                    • Erwartest du Zahlen, prüfe darauf, ob auch Zahlen ankommen. Wenn nicht, ersetze die Eingabe mit einem Vorgabewert oder weise die Eingabe grundsätzlich zurück.
                    • Erwartest du einen String, prüfe auf unerwünschte Werte und behandle die Kontextwechsel, wenn sie anstehen. Eventuell kannst du, abhängig vom Einsatzfall, noch auf Minimal- und/oder Maximallängen der Strings prüfen.
                    • Erwartest du Werte aus einem definierten Bereich (üblicherweise im Falle von Radiobuttons, Checkboxen und Selects), prüfe darauf, ob der Eingabewert laut der Definition des Wertebereichs erlaubt ist oder nicht. Wenn nicht, ersetze die Eingabe mit einem Vorgabewert oder weise die Eingabe grundsätzlich zurück.
                    • Wenn du ein Datum, eine E-Mail-Adresse oder WasAuchImmer mit einer definierten Struktur erwartest, prüfe darauf, ob der Wert dieser Struktur entspricht. Wenn nicht, ersetze die Eingabe mit einem Vorgabewert oder weise die Eingabe grundsätzlich zurück.

                    Du siehst, es gibt einiges mehr zu beachten, als nur „Sonderzeichen“ auszufiltern.

                    Tschö, Auge

                    --
                    200 ist das neue 35.
    2. Hallo,

      vielleicht hilft es in Deinem Fall, eine Erwartung an die Daten zu formulieren?

      Hab dort grad mal eine Pizza nur mit Tomaten bestellt. Landet diese eine Zutat trotzdem in einem Array oder benötigt die is_array-Abfrage in diesem Fall einen else-Zweig?

      Gruß
      Kalk

      1. Hab dort grad mal eine Pizza nur mit Tomaten bestellt.

        Wie hast Du das denn getan?

        $optionen = array(
          #...
          'zutaten' => array('Salami', 'Schinken', 'Paprika', 'Speck')
        );
        
        case 'zutaten':
              if (is_array($value)) {
        
                foreach ($value as $zutat) {
        
                  if (in_array($zutat, $optionen[$key])) {
                    $bestellung[$key][] = $zutat;
                  }
                }
              }
        

        Das ging gar nicht, war nicht vorgesehen. Siehe oben.

        Landet diese eine Zutat trotzdem in einem Array oder benötigt die is_array-Abfrage in diesem Fall einen else-Zweig?

        Auch eine einzelne Zutat landet im Array. Versuche

        <?php
        $zutaten = [ 'Salami', 'Schinken', 'Paprika', 'Speck' ];
        foreach ( $zutaten as $zutat ) {
            echo "
        <label>
            <input type='checkbox' name='zutat[]' value='$zutat'>$zutat
        </label>";
        }
        

        als Formular und du wirst sehen, dass $_POST['zutat'] - sofern der Key in $_POST nach dem Absenden existiert - stets ein Array ist.

        Wenn Du aber meinst, dass Du gar keine Zutat bestellst hast (Hinweis: Es gibt auch weiße Pizzas, also ohne Tomaten): Dann „kommt es darauf an“. Denn je nachdem wie die Formulareingabe verarbeitet wird (Browser oder eigenes JavaScript) gibt es zwei drei denkbare Fälle:

        Nach dem Versenden der Formulardaten und also der automatischen Übernahme der Daten aus php://input sieht $_POST wie folgt aus:

        • $_POST['zutat'] existiert nicht. Folge: Der case tritt im besprochenen Skript nicht ein.
        • $_POST['zutat'] ist ein leerer Array. Der case tritt ergo ein, aber da $_POST['zutat'] leer (oder (Fall 3, „falsche Verarbeitung in JS“:) ein String mit dem Inhalt '[]') ist, geht das foreach ( $_POST['zutat'] as $zutat ) oder schon vorher das if ( is_array() ) ins Leere.

        In beiden allen gezeigten Fällen wird also fehlerfrei keine Zutat zur Bestellung hinzugefügt.

        Das das Skript im Wiki hinsichtlich der Fehlerbehandlung modernen Möglichkeiten nicht mehr im vollen Umfang genügt wurde schon oft genug erwähnt. Diese hinzuzufügen könnte aber auch das Verständnis erschweren.

        1. Hallo,

          Hab dort grad mal eine Pizza nur mit Tomaten bestellt.

          Wie hast Du das denn getan?

          Hab versucht, die einzelnen switchcases zu verstehen und bin über das is_array gestolpert. Aber wenn in allen vorgesehenen Fällen ein Array zutrifft, ist meine Frage wohl beantwortet.

          Gruß
          Kalk

          1. Aber wenn in allen vorgesehenen Fällen ein Array zutrifft, ist meine Frage wohl beantwortet.

            Äh. Nicht ganz:

            • Fall 1: $_POST['zutat'] existiert gar nicht (wird vom case „abgefangen“)
            • Fall 3: $_POST['zutat'] ist ein String '[]'(wird vom if ( is_array () ) abgefangen
            • Fall 2: $_POST['zutat'][n]='Datenmüll' wird vom if ( in_array() ) abgefangen.

            😀 Du kannst vor meinem Anwesen in Ganzgenauheim dagegen protestieren.

  4. Guten Tag,

    Ich schicke Inhalte mittels eines FormDatas vom Client an den Server; - diese landen dann ja in der globalen $_POST Variable.

    Bevor ich deren Inhalt nun sanitize, muss ich irgendwie vorher überprüfen, ob der Client Input überhaupt valide ist?

    Post-Parameter prüfen:

    Validität mit gesicherter Übertragung -> HTTPS, TLS
    Plausibilität hängt von der Applikation ab

    S☼nnige Grüße
    James