Linuchs: Tabellenwerte in <form eingeben

0 44

Tabellenwerte in <form eingeben

Linuchs
  • html
  1. 0
    Raktenbürokratieverbesserer
    1. 0
      Linuchs
      1. 0
        Raketentester
        1. 0
          Linuchs
          1. 0
            Raketentester
            1. 0
              Raketentester
          2. 0
            Linuchs
            1. 0
              Linuchs
            2. 0
              Raketenprogramminspektor
            3. 0
              Matthias Apsel
              1. 0
                Der Martin
  2. -1
    Felix Riesterer
    • html
    • javascript
    • php
    1. 0
      pl
      1. 0
        Felix Riesterer
        1. -1

          Best Practice

          pl
          1. -1

            Best Practice in konkreten Anwendungsfall

            pl
  3. -1
    php
    1. 0
      Felix Riesterer
      1. 0
        pl
      2. 0
        Rolf B
        1. 0
          Felix Riesterer
          1. 0
            Der Martin
            • datenmodell
            • html
            1. 0
              Felix Riesterer
              1. 0
                Rolf B
                1. 0
                  Felix Riesterer
              2. -1

                Requestparameter sind tainted!

                pl
                1. 0
                  Rolf B
                  1. 0
                    pl
                2. 0
                  Raketenchemiker
                  1. 0
                    pl
                    1. 0
                      pl
                      1. 0
                        Raketensicherheitsinspektor
                        1. 0
                          pl
                          1. 0
                            Raketenflugbahnkenner
                    2. 0
                      Raketenhandbuchleser
                      1. 0
                        pl
                        1. 0
                          Raketenhandbuchleser und -Tester
                  2. 0
                    pl
                    1. 0
                      Raketenunsinndiagnostiker
  4. 1
    robertroth
    • datenbank
    • html
    • server
    1. 0
      pl
    2. 0
      Raktensinnsucher
      1. 0
        TS
        • client
        • datenbank
        • server

Moin,

für eine Gema-Meldung sind bis zu 20 Musik-Titel, Komponist usw. einzugeben:

tabelle

Wenn es nur um Titel gehen würde, sähe ein input-Feld so aus:

<input name="titel[]" ...>

Aber ich habe es nun mit einer zweidimensionalen Tabelle zu tun und die Logik wäre eigentlich diese:

<input name="zeile[]['titel']" ...>
<input name="zeile[]['komponist']" ...>
...

Klappt natürlich nicht, var_dump meint, dass 20 * 5 Felder einen Wert hätten:

array(100) {
  [0]=>
  array(1) {
    ["'titel'"]=>
    string(6) "titel1"
  }
  [1]=>
  array(1) {
    ["'komponist'"]=>
    string(2) "k1"
  }
  [2]=>
  array(1) {
    ["'bearbeiter'"]=>
    string(0) ""
  }
  [3]=>
  array(1) {
    ["'verlag'"]=>
    string(2) "m1"
  }
  [4]=>
  array(1) {
    ["'auffuehrungen'"]=>
    string(1) "2"
  }
  [5]=>
  array(1) {
    ["'titel'"]=>
    string(0) ""
  }

Auch die Version ohne ' bringt nicht den gewünschten Erfolg:

<input name="zeile[][titel]" ...>
<input name="zeile[][komponist]" ...>
...

Ist das Eingeben von zweidimensionalen Tabellenwerten gar nicht möglich?

fragt Linuchs

  1. Ist das Eingeben von zweidimensionalen Tabellenwerten gar nicht möglich?

    Lösung 1:

    <input name="zeile[10][titel]" ...>
    <input name="zeile[10][komponist]" ...>
    

    Du musst den Iterator setzen.

    Lösung 2:

    <input name="titel[]" ...>
    <input name="komponist[]" ...>
    

    Du bekommst in (hoffentlich) $POST mehrere Arrays.

    1. Lösung 2:

      War mein erster Gedanke. Aber wenn zeile[0]['komponist'] keine Eingabe hat (nicht immer sind die Komponisten bekannt) dann wäre doch der Komponist aus zeile[1] komponist[0]?

      Also keine Zuordnung zum Titel möglich?

      Linuchs

      1. Weil einfache Aussagen nicht geglaubt werden hab ich das mal schnell für ich getestet:

        <?php
        if ( ! isset( $_POST['komponist'] ) ) {
        ?>
        <form method=POST>
        	<input name="komponist[]"><br>
        	<input name="komponist[]"><br>
        	<input name="komponist[]"><br>
        	<button>senden</button>button>
        </form>
        <?php
        } else {
            header('Content-type: text/plain');
        	print_r( $_POST['komponist'] );
        }
        

        Ergebnis mit erstem und letztem Feld:

        Array
        (
            [0] => Brahms
            [1] => 
            [2] => Beethoven
        )
        
        1. okay, mein Ergebnis mit print_r bei 20 Feldern:

          Array
          (
              [0] => komponist1
              [1] => 
              [2] => komponist3
              [3] => 
              [4] => 
              [5] => 
              [6] => 
              [7] => 
              [8] => 
              [9] => 
              [10] => 
              [11] => 
              [12] => 
              [13] => 
              [14] => 
              [15] => 
              [16] => 
              [17] => 
              [18] => 
              [19] => 
          )
          

          Dann habe ich das falsch in Erinnerung, dass der Browser nur gefüllte Werte sendet. Auch mit var_dump werden alle leeren Felder aufgeführt.

          Verwechsle ich das THema nur gefüllte Werte mit Checkboxen? Da kann man sich NICHT drauf verlassen, dass ab-gehakte Werte gemeldet werden.

          Linuchs

          1. Verwechsle ich das THema nur gefüllte Werte mit Checkboxen? Da kann man sich NICHT drauf verlassen, dass ab-gehakte Werte gemeldet werden.

            Richtig ist:

            Bei Checkboxen kann man sich darauf verlassen, dass nicht selektierte Werte auch nicht gesendet werden:

            Test:

            <?php
            if ( ! isset( $_POST['komponist'] ) ) {
            ?>
            <form method=POST>
            	<input type=checkbox value="Beethoven" name="komponist[]">Beethoven<br>
            	<input type=checkbox value="Mozart" name="komponist[]">Mozart<br>
            	<input type=checkbox value="Brahms" name="komponist[]">Brahms<br>
            	<button>senden</button>
            </form>
            <?php
            } else {
                header('Content-type: text/plain');
            	print_r( $_POST['komponist'] );
            }
            

            Ergebnis:

            Array
            (
                [0] => Beethoven
                [1] => Brahms
            )
            
            1. Im Übrigen bin ich mir fast sicher, dass beim gruppierenden Name die Symbole für die Iteration besser weggelassen werden sollten:

              Also nicht

              <input type="checkbox" name="komponist[]">
              

              sondern:

              <input type="checkbox" name="komponist">
              
          2. Genau. DAS hatte ich im Kopf:

            <input name="bearbeitetjn[]" type="checkbox" ...>
            <input name="bearbeitetjn[]" type="checkbox" ...>
            <input name="bearbeitetjn[]" type="checkbox" ...>
            ...
            

            check

            array(2) {
              [0]=>
              string(1) "1"
              [1]=>
              string(1) "1"
            }
            

            Merkwürdig, (genauer: merkpflichtig) diese extrem unterschiedliche Logik.

            Linuchs

            1. okay, kann man überlisten:

              <input name="bearbeitetjn[1]" type="checkbox" ...>
              <input name="bearbeitetjn[2]" type="checkbox" ...>
              <input name="bearbeitetjn[3]" type="checkbox" ...>
              ...
              
              array(2) {
                [1]=>
                string(1) "1"
                [3]=>
                string(1) "1"
              }
              

              Linuchs

            2. Dann nimm Lösung 1.

              Suboptimal (möglich, aber verwirrend und also fehlerträchtig) wäre es nämlich im auswertenden Skript die Elemente des Arrays anders zu adressieren.

            3. Hallo Linuchs,

              Merkwürdig, (genauer: merkpflichtig) diese extrem unterschiedliche Logik.

              Warum ist sie extrem unterschiedlich? Es könnte doch sein, dass du einen leeren String übertragen möchtest. Grundsätzlich werden name-value-Paare übertragen. Wenn eine Checkbox angeklickt ist, wird Name der Checkbox-on übertragen. Sonst nichts.

              Bis demnächst
              Matthias

              --
              Du kannst das Projekt SELFHTML unterstützen,
              indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
              1. Hallo Matthias,

                Merkwürdig, (genauer: merkpflichtig) diese extrem unterschiedliche Logik.

                Warum ist sie extrem unterschiedlich?

                das frag besser diejenigen, die das so festgelegt haben. ;-)

                Es könnte doch sein, dass du einen leeren String übertragen möchtest.

                Richtig, deswegen werden leere Textfelder im Query-String auch nicht weggelassen.

                Grundsätzlich werden name-value-Paare übertragen. Wenn eine Checkbox angeklickt ist, wird Name der Checkbox-on übertragen. Sonst nichts.

                So ist es spezifiziert. Ich halte aber ebenso die Erwartungshaltung für nachvollziehbar, dass nicht gewählte Checkboxen ihren Namen und ein leeres value-Feld übermitteln. Das würde dem Verhalten von Textfeldern entsprechen.
                Ist nicht so, ich weiß, aber ich sehe ebenso wie Linuchs einen Unterschied im Verhalten, den ich nicht wirklich logisch oder konsequent finde.

                Schönen Sonntag,
                 Martin

                --
                Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
  2. Lieber Linuchs,

    man kann es auch gleich richtig(TM) machen...

    <input name="titel[]" ...>
    

    Das ist PHP-spezifisch. Das kann man so machen, muss man aber nicht.

    <input name="zeile[]['titel']" ...>
    <input name="zeile[]['komponist']" ...>
    ...
    

    Siehst Du, da sollte man doch nicht PHP überlassen, wie die Array-Struktur aufgebaut werden sollte. In meinem Fall sieht das so aus:

    <input name="data-123-title" ...>
    <input name="data-123-composer" ...>
    <input name="data-123-year" ...>
    <input name="data-123-whatever" ...>
    

    Das erzeugt entsprechende $_POST-Schlüssel, die ich dann schön der Reihe nach "parsen" kann. Was nicht passt, wird nicht erkannt und kann meine Array(s) nicht vermüllen:

    $data = array();
    
    foreach ($_POST as $key => $value) {
    
      if (preg_match('~^data-(\d+)-([a-z]+)$~', $key, $found)) {
    
        // $found[1] hat Datensatz-Nummer
        // $found[2] hat Attribut-Namen
    
        // default-Datensatz anlegen
        if (!array_key_exists($found[1], $data)) {
          $data[$found[1]] = array(
            'composer' => '',
            'title' => '',
            'whatever' => '',
            'year' => ''
          );
        }
    
        // existiert so ein Attributname?
        if (array_key_exists($found[2], $data[$found[1]])) {
          $data[$found[1]][$found[2]] = $value;
        }
      }
    }
    

    Mit dieser Vorgehensweise gibt es kein "glauben, dass es tut", sondern absolute Gewissheit über jeden kleinsten Einzelschritt, sowie Sicherheit darüber, dass nichts an weiterem bösen User-Input unpassenderweise hinein kommt. Und das Zuckerli ist noch, dass die Array-Schlüssel Deinen DB-Schlüsseln entsprechen.

    Für Neuaufnahmen nimmst Du das Schlüsselwort "new", das ein Array "new" erzeugt, welches Du dann später als Neuaufnahme interpretieren und speichern kannst. Sollen mehrere neue Datensätze aufgenommen werden können, nimmst Du eben fortlaufend nummerierte Schlüssel "new2", "new3" (oder "new-2", "new-3") usw. Auch das kann man später beim Speichern berücksichtigen. Solche "new2" und "new3" könnten von Formularen kommen, die mit JavaScript zusätzlich benötigte Eingabefelder erhalten haben.

    Liebe Grüße

    Felix Riesterer

    1. hi,

      Siehst Du, da sollte man doch nicht PHP überlassen, wie die Array-Struktur aufgebaut werden sollte. In meinem Fall sieht das so aus:

      <input name="data-123-title" ...>
      <input name="data-123-composer" ...>
      <input name="data-123-year" ...>
      <input name="data-123-whatever" ...>
      

      Das erzeugt entsprechende $_POST-Schlüssel, die ich dann schön der Reihe nach "parsen" kann. Was nicht passt, wird nicht erkannt und kann meine Array(s) nicht vermüllen:

      Warum das Rad neu erfinden? Warum nicht gleich so:

       <input name="data[123][title]" ...>
       <input name="data[123][composer]" ...>
       <input name="data][123][year]" ...>
       <input name="data][123][whatever]" ...>
      

      Und das parst PHP. Ein Eigenbau'Parser ist unnötig!

      MFG

      1. Lieber pl,

        Und das parst PHP. Ein Eigenbau'Parser ist unnötig!

        egal, was PHP geparst hat, ich muss doch überprüfen, ob die Struktur die ist, die ich auch haben möchte. Und wenn ich schon dabei bin, kann ich das auch gleich so tun, dass PHP mir nicht zuerst etwas unterjubelt, was ich danach wieder entfernen muss.

        Liebe Grüße

        Felix Riesterer

        1. Die Geschäftslogik einer Webanwendung wird auf Parameten abgebildet. Ebenso befinden sich Nutzdaten, Benutzereingaben in Parametern. Und jeder Request bringt noch eine ganze Reihe weiterer Parameter mit die in einer Anwendung überhaupt gar keine Rolle spielen.

          Die ganze Validierung eines Requests beginnt schon mit der Planung, namentlich damit daß man für den Programmablauf sog. Schlüsselparameter festlegt und über diese Schlüsselparameter eine Kontrollstruktur legt. So sind diese Schlüsselparameter von den Parametern die Nutzdaten enthalten sauber getrennt.

          Leider ist es so, daß die Enctypes application/x-www-form-urlencoded und multipart/form-data als die Einzigen strukturierten Content-Types gerade in dieser Hinsicht gar keine Unterstützung bieten. Von daher geht ja PHP den Weg der Strukturierung über eine bestimmte Namensgebung für die Parameter (in Perl übrigens auch).

          So kann man über eine entsprechende Namensgebung die Schlüsselparameter von den Datenparametern sauber trennen. Z.B. so, daß alle Schlüsselparameter unter $_POST['prog']['key'] zu finden sind und die Nutzdaten unter $_POST['user']['name'] usw.

          MFG

          1. Hinsichtlich einer Trennung von Programmierlogik, Schlüsselparameter und Benutzereingaben bietet es sich hier im konkreten Anwendungsfall an, die Tabellendaten im Bowser (Objekt) zu halten und bei einem Update dieses Datenobjekt als JSON serialisiert im Request-Message-Body per POST zu senden. Enctype: application/json

            Die Schlüsselparameter hingegen werden als QUERY_STRING an den URL gehängt und serverseitig wie in PHP üblich aus $_GET gelesen. Serverseitig wird das Datenobjekt mit json_decode() wiederhergestellt.

            MFG

  3. Das Strukurieren von Requestparametern geht mit PHP besonders gut zu machen. Man muss den Inputfeldern nur die richtigen Namen geben.

    Array
    (
        [person] => Array
            (
                [vname] => Henry
                [lastname] => Eiswürfel
            )
    
        [addr] => Array
            (
                [str] => Main-Street
                [plz] => PO-1234
                [ort] => Array
                    (
                        [base] => Urbia
                        [stadtbezirk] => Sub-Urbia
                    )
    
            )
    
        [colors] => Array
            (
                [red] => red
                [green] => green
                [blue] => blue
            )
    
        [dump] => 1
    )
    
    Erläuterungen
    
    Infolge de Namensgebung de Inputfelder:
    
    <input name="person[vname]">
    <input name="person[lastname]">
    <input name="addr[str]">
    <input name="addr[plz]">
    <input name="addr[ort][base]">
    <input name="addr[ort][stadtbezirk]">
    <input name="colors[red]" type="checkbox">
    <input name="colors[green]" type="checkbox">
    <input name="colors[blue]" type="checkbox">
    
    Erzeugt der Parser von PHP beim Absenden des Formulars die obenstehende Datenstruktur. 
    

    Und den $POST natürlcih auch richtig auswerten.

    MFG

    1. Lieber pl,

      <input name="addr[ort][base]">
      

      sehr schön. Und wenn ein pöhser Pube in seinen POST-Daten noch ein addr[ort][foo]=bar injiziert, steht das in Deinen erhaltenen Daten, obwohl Du das nicht da drin haben willst. Ich gratuliere Dir zu Deiner user input sanitation strategy.

      Liebe Grüße

      Felix Riesterer

      1. <input name="addr[ort][base]">
        

        sehr schön. Und wenn ein pöhser Pube in seinen POST-Daten noch ein addr[ort][foo]=bar injiziert, steht das in Deinen erhaltenen Daten, obwohl Du das nicht da drin haben willst. Ich gratuliere Dir zu Deiner user input sanitation strategy.

        Wie ich schrieb, jeder Request ist am Server entsprechend auszuwerten. Eine Validierung muss grundsätzlich immer erfolgen, egal in welcher Struktur Daten zu erwarten sind oder vorliegen.

        MFG

      2. Hallo Felix,

        ich habe gerade etwas mit der Kanüle herumgestochert, aber so schlimm wie Du meinst scheint es nicht zu sein.

        Ein name="foo[bar][$a=6]" führt zu einem Array-Key "$a=6", und in name="foo[bar][baz]=6" wird das =6 ignoriert.

        Auch ein Name wie name="$foo[bar][baz]" ist unproblematisch, selbst wenn man zu Beginn des Scripts noch $foo="Hugo" setzt. Es entsteht ein Key "$foo" im $_POST Array.

        Namen wie $foo->baz oder foo->baz führen nicht zu Objektzugriffen, sondern zu $_POST Keys dieses Namens. Da wird also ganz strikt die Grammatik

        name: VARNAME index*;  
        INDEX: '[' [^\]]* ']';
        

        angewendet, und ja, der Variablenname im Index ist jedesmal optional. name="foo[][]" ist erlaubt und führt zu $_POST['foo'][0][0].

        Rolf

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

          ich glaube, Du hast mich missverstanden. Mir ging es nicht um schräge Elementnamen in HTML, mir ging es um auf anderem Wege erzeugte POST-Requests, in denen präparierte Namen für zusätzliche Array-Schlüssel enthalten sind. Einfach um das Ziel-Array mit zusätzlichen Werten zu befüllen.

          Es gilt nach wie vor die Grundregel, dass gesendete Daten kritisch zu prüfen sind. Das hat hier auch niemand angezweifelt. Mein Punkt ist, dass man ja ohnehin kritisch prüft und dabei die vorhandenen Daten anhand einer vorgegebenen Struktur abnehmen sollte, anstatt sich auf den PHP-Mechanismus zu verlassen. Dann kann man es auch gleich so machen, wie ich beschrieben habe.

          Liebe Grüße

          Felix Riesterer

          1. Hallo Felix,

            ich glaube, Du hast mich missverstanden. Mir ging es nicht um schräge Elementnamen in HTML, mir ging es um auf anderem Wege erzeugte POST-Requests, in denen präparierte Namen für zusätzliche Array-Schlüssel enthalten sind. Einfach um das Ziel-Array mit zusätzlichen Werten zu befüllen.

            und was soll dann passieren - außer dass ein paar Bytes unnütz übermittelt werden?

            Wenn Parameter übertragen werden, die die Ziel-Applikation nicht kennt, fragt sie auch nicht danach. Folglich werden diese Request-Parameter einfach ignoriert.

            Es gilt nach wie vor die Grundregel, dass gesendete Daten kritisch zu prüfen sind.

            Völlig klar. Aber willst du andeuten, dass man auch abprüfen sollte, ob zusätzliche, unbekannte Parameter angekommen sind?

            Mein Punkt ist, dass man ja ohnehin kritisch prüft und dabei die vorhandenen Daten anhand einer vorgegebenen Struktur abnehmen sollte, anstatt sich auf den PHP-Mechanismus zu verlassen. Dann kann man es auch gleich so machen, wie ich beschrieben habe.

            Kann man natürlich. Aber mir erschließt sich der Sinn nicht.

            Schönen Abend noch,
             Martin

            --
            Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
            1. Lieber Martin,

              Aber willst du andeuten, dass man auch abprüfen sollte, ob zusätzliche, unbekannte Parameter angekommen sind?

              ich gehe davon aus, dass hier im Wesentlichen Hobbyisten mitlesen, die vielleicht die Bequemlichkeit in Anspruch nehmen möchten, die der Mechanismus von PHP bietet, indem er verschachtelte Array-Strukturen über entsprechend gestaltete Indices in den POST-Daten erstellt. Wenn die Bequemlichkeit dann auch noch so weit geht, dass man blind darauf vertraut, dass die Struktur immer so aussieht, wie man das im Idealfall gerne möchte, kann das schwierig bis gefährlich werden.

              Beispiel:

              // erwartete Struktur
              $_POST['data'] = [
                'what' => [
                  'who' => string,
                  'age' => integer
                  'txt' => string
                ],
                'how' => string
              ];
              

              Wenn nun die POST-Daten so aussehen (für bessere Lesbarkeit habe ich Zeilenumbrüche eingefügt), dann kommt es sehr darauf an, was Deine Applikation damit macht:

              data[what][who]=nobody
              &data[what][age]=confidential
              &data[what][txt]=I%20disagree%20completely!
              &data[how]=save
              &data[bogus][nonsense]=bad%20SQL%20code
              

              Auf PHP-Seite ergäbe das folgende Struktur:

              // erhaltene Struktur
              $_POST['data'] = [
                'what' => [
                  'who' => 'nobody',
                  'age' => 'confidential', // kein Integer!
                  'txt' => 'I disagree completely!'
                ],
                'how' => 'save',
                // unerwartetes Teilarray!
                'bogus' => [
                  'nonsense' => 'bad SQL code'
                ]
              ];
              

              Nicht nur sehen wir, dass $_POST['data']['who']['age'] keinen zu Integer passenden Wert enthält, wir finden auch ein weiteres Teilarray $_POST['data']['bogus'], welches wir nicht erwartet haben. Wenn wir nun blind aus dem Array SQL-Statements bauen, die etwas in die Datenbank schreiben, dann führt das eventuell zu Programmfehlern.

              Daher darf man sich meiner Meinung nach nie auf die generierte Array-Struktur verlassen. Dass @Linuchs mit dem PHP-Mechanismus ein grundlegenderes Problem hat, weil er sich nicht sicher ist, wie er Feldnamen gestalten soll, damit eine für ihn irgendwie verarbeitbare Array-Struktur entsteht, kann man gleich damit lösen, dass man diesen Mechanismus als unzuverlässig verteufelt, um solche Unsicherheiten und Angriffsmöglichkeiten von vornherein auszuschließen.

              Liebe Grüße

              Felix Riesterer

              1. Hallo Felix,

                ok, ich hätte gedacht du wolltest vor Codeinjektionen durch böse Namen warnen. Angesichts der Historie von PHP ist ein solches Loch durchaus vorstellbar.

                Dass jemand direkt aus dem $_POST Array SQL generiert, darauf wäre ich nun nicht gekommen. Aber Deppen, die solche „genialen“ Ideen haben und vielleicht auch noch anpreisen, gibt's im wirren weiten Web genug.

                Die rettest du aber auch nicht mit deinem Namenskonzept. Ob ich foo-123-name schreibe und daraus SQL generiere oder ngc[1701][captain][1] ändert nichts, solange man stumpf generiert.

                Rolf

                --
                sumpsi - posui - clusi

                1. ja Gunnar, dieser Index ist ggf nicht numerisch ↩︎

                1. Lieber Rolf,

                  Dass jemand direkt aus dem $_POST Array SQL generiert, darauf wäre ich nun nicht gekommen. Aber Deppen, die solche „genialen“ Ideen haben und vielleicht auch noch anpreisen, gibt's im wirren weiten Web genug.

                  leider.

                  Die rettest du aber auch nicht mit deinem Namenskonzept. Ob ich foo-123-name schreibe und daraus SQL generiere oder ngc[1701][captain][^1] ändert nichts, solange man stumpf generiert.

                  Das ist richtig. Aber mit meinem Namenskonzept geht ja auch ein selbstgeschriebenes Parsen mit, welches in meinem Beispiel streng nach einer vorgegebenen Struktur prüft und nur erlaubtes finden kann. Wenn ich den PHP-Mechanismus nutze, entfällt diese Notwendigkeit. Da muss ich das bereits erstellte Array "parsen" (lies: abarbeiten), um dessen Inhalte nach meiner vorgegebenen Struktur auszulesen. Der Aufwand ist dabei fast derselbe, wie das eigene Konzept. Und wenn sich jemand dieses Konzept antut, dann ist er ohnehin schon dabei, unzulässiges zu filtern. Und wenn er bequem sein will, lässt er PHP die Arbeit verrichten und prüft anschließend noch nicht einmal, ob da nicht verbotenes enthalten ist. Daher argumentiere ich, dass man die Bequemlichkeit vermeiden sollte, da ihre Vermeidung das Potenzial hat, sichereren Code zu verursachen.

                  Liebe Grüße

                  Felix Riesterer

              2. HTTP kennt keine Integer sondern nur Strings. $_POST/$_GET Parameter sind gundsätzlich nur Strings. Eine Validierung kann jedoch prüfen ob die Umwandlung nach einem Integer fehlerfrei möglich ist.

                Im Übrigen ist alles, was von draußen in eine Anwendung eingebracht wird als tainted zu berachten. Das sind nicht nur Parameter in GET/POST sondern auch der URL selbst, der HTTPmessageBody, Cookies und alle übrigen Parameter die der Webserver als Umgebungsvariablen bereitstellt ($_SERVER). Und auch Dateien die mit require/include eingebunden werden sind tainted!

                Und auch Konfigurationsdateien!

                MFG

                1. Hallo pl,

                  jetzt machst Du den Stoiber (mann was hat der mich gestern bei Hart aber Fair genervt) und waberst mit dem Thema durch die Gegend.

                  Was über die User-Schnittstelle kommt (HTTP, FTP, werweißwassonst), ist besudelt (tainted) und zur Laufzeit zu prüfen. Einverstanden.

                  Was vom Autor kommt, muss zur Laufzeit aber nicht geprüft werden. Mir selbst vertraue ich sowieso. Und wenn ich jemand anderem soweit vertraue, dass ich das Recht erteile, nichtöffentliche Teile des Webs zu lesen oder sogar zu verändern, dann muss ich auch darauf vertrauen, dass dieses Recht nicht zum Besudeln der Site missbraucht wird.

                  Es kann natürlich Tippfehler geben. Oder Config-Keys, die zu setzen vergessen wurden. Eine Anwendung sollte fehlende Config-Einträge sinnvoll reporten. Aber das ist nicht „tainted“. Tainted wäre eine Config-Datei, oder eine externen Klassenbibliothek, die dazu führt, dass Daten entgegen dem Zweck der Site genutzt werden. Oder Schadcode an User geliefert wird.

                  Das kann ich aber nicht durch Laufzeitprüfungen bekämpfen. Da hilft nur Inspektion und Test der genutzten Fremdkomponenten, bevor sie in mein Web kommen.

                  Rolf

                  --
                  sumpsi - posui - clusi
                  1. Was vom Autor kommt, muss zur Laufzeit aber nicht geprüft werden.

                    Genau das ist der Denkfehler!

                    MFG

                  • Requestparameter sind tainted!
                  • Und auch Konfigurationsdateien!

                  Ich sags mal so:

                  Das ist die Herangehensweise von [Perl -tT]. Bei den Konfigurationsdateien würde ich sehr stark zu einer Einzelfallbetrachtung neigen. Immerhin darf da ja nicht jeder mal eben was reinschreiben weil es so lustige Auswirkungen hat. Und wenn man selbst diese stets als vergiftet zu betrachten hat, dann kann man ihnen auch nicht trauen und ergo macht die gesamte Konfiguration dann keinen Sinn mehr…

                  • und alle übrigen Parameter die der Webserver als Umgebungsvariablen bereitstellt ($_SERVER)

                  Das kommt doch wohl stark auf die Items an. Wenn z.B. in S_SERVER['REQUEST_TIME'] etwas anderes als ein Integer mit den Sekunden seit dem 1.1.1970 00:00:00 auftaucht, dann hat man regelmäßig ein ganz anderes Problem...

                    • Requestparameter sind tainted!
                    • Und auch Konfigurationsdateien!

                    Ich sags mal so:

                    Das ist die Herangehensweise von [Perl -tT].

                    Tainted hat nichts mit perl -t zu tun. Im Übrigen ist auch der Domänenname (HOST, SERVER_NAME) tainted, spätestens seit es Punycode und Umlautdomänen gibt. in der C't gabs neulich erst einen Artikel darüber.

                    Bei den Konfigurationsdateien würde ich sehr stark zu einer Einzelfallbetrachtung neigen. Immerhin darf da ja nicht jeder mal eben was reinschreiben weil es so lustige Auswirkungen hat. Und wenn man selbst diese stets als vergiftet zu betrachten hat, dann kann man ihnen auch nicht trauen und ergo macht die gesamte Konfiguration dann keinen Sinn mehr…

                    Nun, Vertrauen und Prüfen sind bekanntlich 2 verschiedene Dings.

                    • und alle übrigen Parameter die der Webserver als Umgebungsvariablen bereitstellt ($_SERVER)

                    Das kommt doch wohl stark auf die Items an. Wenn z.B. in S_SERVER['REQUEST_TIME'] etwas anderes als ein Integer mit den Sekunden seit dem 1.1.1970 00:00:00 auftaucht, dann hat man regelmäßig ein ganz anderes Problem...

                    Wie gesagt, HTTP kennt keine Integer.

                    MFG

                    1. punicode pishing

                      beschreibt das und zeigt daß auch die Domänennamen tainted sind. MFG

                      1. punicode pishing

                        beschreibt das und zeigt daß auch die Domänennamen tainted sind. MFG

                        Deine originale Aussage war:

                        Im Übrigen ist auch der Domänenname (HOST, SERVER_NAME) tainted,

                        So lange Du als Systemverwalter auf dem Default-Host des Apache gar nichts außer dem üblichen 404er oder einer andere statischen Seite auslieferst und in der Konfiguration des virtuellen Hosts den Servername gesetzt hast, kann gar nichts passieren. Denn Zugriffe auf die IP oder mit dem falschen Hostname (die landen alle beim Default-Host) erfolgen normalerweise entweder versehentlich oder sind Tests auf Angriffsmöglichkeiten.

                        Wie auch immer: Durch das Konfigurieren eines virtuellen Hosts kommen da nur Anfragen nach dem definierten Host oder einem ebenfalls selbst definierten Alias überhaupt an.

                        Wenn Du als Du als Systemverwalter aber DERZEIT auf dem Default-Host allen Ernstes IMMER NOCH die Website selbst auslieferst, dann solltest Du dieses Vorgehen SEHR GENAU überdenken.

                        Und wenn Du das sehr genau und also mit dem richtigen Ergebnis bedacht und ein wenig im PHP-Handbuch gelesen hast und entsprechend gehandelt hast, dann ist $_SERVER['SERVER_NAME'] nicht mehr tainted.

                        Die von Dir vorgeschlagene Suche nach 'punicode pishing' führt zu Problembeschreibungen, die mit dem vorliegenden Sachverhalt nichts zu tun haben.

                        1. Und wenn Du das sehr genau und also mit dem richtigen Ergebnis bedacht und ein wenig im PHP-Handbuch gelesen hast und entsprechend gehandelt hast, dann ist $_SERVER['SERVER_NAME'] nicht mehr tainted.

                          Da steht nirgendwo etwas von untainted! Im Übrigen implementiert auch PHP nur einen Standard nämlich den in CGI/1.1

                          MFG

                          1. Und wenn Du das sehr genau und also mit dem richtigen Ergebnis bedacht und ein wenig im PHP-Handbuch gelesen hast und entsprechend gehandelt hast, dann ist $_SERVER['SERVER_NAME'] nicht mehr tainted.

                            Da steht nirgendwo etwas von untainted! Im Übrigen implementiert auch PHP nur einen Standard nämlich den in CGI/1.1

                            Dann bedenke mal den Weg der Daten:

                            1. Der Apache bekommt mit dem Request einen Hostname.
                            2. Der Apache vergleicht diesen übermittelten Hostname mit dem Hostnamen und Aliasnamen der vom Systenverwalter konfigurierten virtuellen Hosts.
                            3. Nur wenn eine bytegenaue Übereinstimmung vorliegt liefert der Apache eine Webseite eines konfigurierten virtuellen Hosts aus, sonst die des Default-Hosts (also auf Grund des oben stehenden nur eine statische Fehlermeldung) $_SERVER['SERVER_NAME'] wird, weil PHP nicht mal bemüht wird, also gar nicht erst besetzt.
                            4. Aus 2. und 3. folgt zwingend, dass ein anderer Fall gar nicht auftreten kann, weil sonst das Skript gar nicht erst aufgerufen wird.
                            5. Aus 2, und 3. folgt zwingend, dass in $_SERVER['SERVER_NAME'] stets genau ein vom Systemverwalter konfigurierter also gesetzter String steht. Der ist per Definition „nicht vergiftet“.

                            Was zu beweisen war.

                    2. Das kommt doch wohl stark auf die Items an. Wenn z.B. in S_SERVER['REQUEST_TIME'] etwas anderes als ein Integer mit den Sekunden seit dem 1.1.1970 00:00:00 auftaucht, dann hat man regelmäßig ein ganz anderes Problem...

                      Wie gesagt, HTTP kennt keine Integer.

                      Das angesprochene S_SERVER['REQUEST_TIME'] wird von PHP durch einen syscall auf time() ermittelt, hat als Datentyp stets Integer und hat insofern mit dem HTTP-Protokoll "höchstens nur sehr indirekt" zu tun, denn die Inhaltsermittlung erfolgt NACH dem Eintreffen des HTTP-Requests und benutzt dessen Inhalt nicht, sondern die Kernel-API des OS. Bitte schlage sowas künftig nach oder teste ein wenig bevor Du hier auftrumpfend unzutreffende Mutmaßungen verbreitest.

                      1. Das kommt doch wohl stark auf die Items an. Wenn z.B. in S_SERVER['REQUEST_TIME'] etwas anderes als ein Integer mit den Sekunden seit dem 1.1.1970 00:00:00 auftaucht, dann hat man regelmäßig ein ganz anderes Problem...

                        Wie gesagt, HTTP kennt keine Integer.

                        Das angesprochene S_SERVER['REQUEST_TIME'] wird von PHP durch einen syscall auf time() ermittelt, hat als Datentyp stets Integer und hat insofern mit dem HTTP-Protokoll "höchstens nur sehr indirekt" zu tun, denn die Inhaltsermittlung erfolgt NACH dem Eintreffen des HTTP-Requests und benutzt dessen Inhalt nicht, sondern die Kernel-API des OS. Bitte schlage sowas künftig nach oder teste ein wenig bevor Du hier auftrumpfend unzutreffende Mutmaßungen verbreitest.

                        In meiner Serverumgebung ist REQUEST_TIME gar nicht gesetzt. Und wenn, dann wäre das noch lange kein integer sondern allenfalls eine Folge von Ziffern, also in String. Dabei ist es unerheblich ob diese Zeitangabe aus einem syscall resultiert oder von sonstwoher ermittelt wird.

                        HTTP kennt nur Strings.

                        1. HTTP kennt nur Strings.

                          Nochmal für Dich: S_SERVER['REQUEST_TIME'] hat mit den, durch das HTTP-Protokoll übermittelten Daten NICHTS zu tun.

                          Und wenn, dann wäre das noch lange kein integer sondern allenfalls eine Folge von Ziffern, also in String.

                          Wenn Du diese, objektiv und leicht überprüfbar falsche Aussage auch noch tausende Male wiederholst, dann wird diese davon nicht richtiger. Die Ausgabe von var_dump($_SERVER['REQUEST_TIME']):

                          int(1580814096)
                          

                          ist eindeutig ein Integer, die von $_SERVER['REQUEST_TIME_FLOAT'] ein Float. Also gerade kein String!

                          In meiner Serverumgebung ist REQUEST_TIME gar nicht gesetzt.

                          Dann solltest Du Deinem PHP endlich ein Update gönnen. Verfügbar ist $_SERVER['REQUEST_TIME'] seit PHP 5.1., aktuell ist Version 7.4.

                  1. Das kommt doch wohl stark auf die Items an. Wenn z.B. in S_SERVER['REQUEST_TIME'] etwas anderes als ein Integer mit den Sekunden seit dem 1.1.1970 00:00:00 auftaucht, dann hat man regelmäßig ein ganz anderes Problem...

                    Eben! Genau deswegen ist SERVER_TIME tainted und muss vor Verwendung geprüft werden.

                    Genauso wie jede andere Umgebungsvariable.

                    1. Das kommt doch wohl stark auf die Items an. Wenn z.B. in S_SERVER['REQUEST_TIME'] etwas anderes als ein Integer mit den Sekunden seit dem 1.1.1970 00:00:00 auftaucht, dann hat man regelmäßig ein ganz anderes Problem...

                      Eben! Genau deswegen ist SERVER_TIME tainted und muss vor Verwendung geprüft werden.

                      Willst Du "Intrusion Detection" an der nutzlosesten Stelle betreiben oder was?

                      Wenn S_SERVER['REQUEST_TIME'] vergiftet ist, dann gibt es dafür nur drei Wege:

                      • PHP wurde vom Angreifer durch etwas anderes ersetzt.
                      • Die libc wurde vom Angreifer durch etwas anderes ersetzt.
                      • Der Kernel wurde vom Angreifer durch etwas anderes ersetzt.

                      Für all das braucht der Angreifer sehr umfassende Rechte. Das meinte ich mit „dann hat man regelmäßig ein ganz anderes Problem...“ - und ich vermute mal, dass ein Angreifer nicht unbedingt an der Uhr herumschraubt.

  4. Lieber Linuchs,

    als Index würde ich auf jeden Fall immer die ID des Datensatzes aus der Datenbank benutzen. Siehe auch die Antworten vom Raketenmann.

    Tabellarische Bearbeitungen führen aber meistens dazu, dass man der Datenbank unnötig Arbeit bereitet, wenn man keine besonderen Vorkehrungen trifft. Es müssen dann schließlich auch diejenigen Datensätze neu geschrieben (UPDATE) werden, die sich gar nicht verändert haben.

    Spirituelle Grüße
    Dein Robert

    --
    Möge der Forumsgeist ewig leben!
    1. Idee: Über eine Checksumme feststellen, ob überhaupt Daten verändert wurden. Jeder Editor zeigt in der Titelzeile an, ob die geladene Datei geändert wurde, z.B. mit einem Sternchen am Dateinamen.

      Genauso kann man das mit einer Tabelle im Browser machen, so daß bereits der Anwender sieht ob er überhaupt was geändert hat und ein Update rausschicken muss oder nicht.

      MFG

    2. Es müssen dann schließlich auch diejenigen Datensätze neu geschrieben (UPDATE) werden, die sich gar nicht verändert haben.

      Die meisten Datenbank[managment]systeme selbst schreiben bei einem Update ohne tatsächliche Veränderungen nichts neu:

      Beispiel von mariadb:

      Rows matched: 1  Changed: 0  Warnings: 0
      

      Allerdings muss dem Datenbank[managment]system der Wunsch nach Veränderung übermittelt werden, was durchaus Zeit kostet. Stellt sich die Frage, wie häufig das vorkommt und ob es sich überhaupt lohnt, da gegenzusteuern:

      Query OK, 0 rows affected (0.01 sec)
      

      Komplizierte Operationen mit Hash bauen und vergleichen (wie von PL vorgeschlagen) könnten sogar teurer werden, fressen auf jeden Fall Programmierzeit und führen vielleicht oft zu eigenen Fehlern.

      1. Hello,

        Das ist weinger, als die halbe Wahrheit.

        Ich hatte eben detailliert beschrieben, welche Probleme eine tabellarische Bearbeitung mit sich bringt.

        Leider ist die Connection (wie schon öfter) abgebrochen.

        Komme später nochmal darauf zurück

        hier nicht tabellarisch editieren!

        Glück Auf
        Tom vom Berg

        --
        Es gibt nichts Gutes, außer man tut es!
        Das Leben selbst ist der Sinn.