Alain: formular - value und name modern parsen

Hallo,
Ich habe mir ein perlscript zusammen gebastelt.
Gebastelt kann man so nicht sagen da ich zum einen
#!/usr/bin/perl -Tw
use strict;
use CGI::Carp qw(fatalsToBrowser);

verwende und es funktioniert tadellos.
Meine frage diesbezüglich ist,ob da nicht eventuell zuviel im sub parse drinn steht,
wenn ich mir die parse funktion bei selfhtml http://selfhtml.teamone.de/cgiperl/intro/cgihtml.htm#wechselwirkung_html_cgi
ansehe,dann siehts dort erheblich einfacher aus.
Ich füge mal meinen code unten hin zur einsicht:
my %input = parse_form();
sub parse_form {
   my ($len, $meth, $type, $input);
   my %input;

# Read three useful environment variables
   $type = $ENV{'CONTENT_TYPE'};
   $len  = $ENV{'CONTENT_LENGTH'};
   $meth = $ENV{'REQUEST_METHOD'};

if ($len > 300)  {
       die("error was found 3\n");
   }

if ($type eq 'application/x-www-form-urlencoded' || $type eq '' )   {
 my ($value, $i);

# Read in text
     if ($meth eq 'POST') {
     read(STDIN, $input, $len);
     }
     else  {
     die("error was found 2\n");
     }

#Split @in into multiple fields.
     my @vars = split(/[&;]/,$input);

foreach $i (0 .. $#vars)  {
     # Convert plus to space
     $vars[$i] =~ s/+/ /g;

# Convert %XX from hex numbers to a character
     $vars[$i] =~ s/%(..)/pack("c",hex($1))/ge;
  my ($name, $value) = split /=/, $vars[$i];
  $input{$name} = $value;
      }
   }
   else   {
      die("error was found 1");
   }

return %input;
}
---------------------------
Gruss
vom Alain

  1. moin,,

    Ich habe mir ein perlscript zusammen gebastelt.
    Gebastelt kann man so nicht sagen da ich zum einen
    #!/usr/bin/perl -Tw
    use strict;
    use CGI::Carp qw(fatalsToBrowser);

    verwende und es funktioniert tadellos.
    Meine frage diesbezüglich ist,ob da nicht eventuell zuviel im sub parse drinn steht,
    wenn ich mir die parse funktion bei selfhtml

    eine eigene parse() Funktion nehme ich kaum noch. Und wenn du ohnehin das CGI Modul verwendest, kannst du mit

    use CGI 'param';

    und dann mit

    my $name = param('name');

    den Wert eines jeden Inputfeldes bekommen.

    /rolf

    --
    SELFforum - Das Tor zur Welt!
    Theoretiker: Wie kommt das Kupfer in die Leitung?
    Praktiker: Wie kommt der Strom in die Leitung?
  2. Moin.

    Ich benutze gern eine der beiden folgen Varianten. Mein 1. parse_form erzeugt für jeden übergebenen Parameter eine Variable mit dem entsprechenden Namen und dem Wert. Das funktioniert für Skalare ebenso wie für Arrays, allerdings nicht mit "use strict", da Du im Script Variablen benutzt, die nicht mit 'my' erzeugt wurden.

    Hast Du im Formular folgende Zeile
    <input type="text" name="einBeispiel" value="blabla">,
    dann steht nach Aufruf von parse_form in der Variablen $einBeispiel der String "blabla" und Du kannst ihn "einfach benutzen":

    use CGI;
    &parse_form();
    print $einBeispiel;

    sub parse_form {
       # alle Namen der übergebenen Parameter lesen
       my @names = $form->param;
       # für alle übergebenen Parameter...
       foreach (@names){
          # ... die Werte erstmal in ein Array lesen
          my @value = $form->param($_);
          # testen, ob Skalar oder Array
          if ((scalar @value ) > 1 ){
            # Array erzeugen mit dem Namen des zugehörigen Parameters
            # und Value speichern
            @$_ = @value;
          }else{
            # Skalar erzeugen mit dem Namen des zugehörigen Parameters
            # und Value speichern
            $$_ = $value[0];
          }
       }
    }

    Mit keinen Änderungen ist dieses "Verfahren" auch mit "use strict" nutzbar. Du mußt Dir einen Hash mit 'my' anlegen, die Namen der Formularfelder werden als Keys verwendet. Der Zugriff erfolgt dann wie gehabt:

    use CGI;
    my %input = parse_form();
    print $input{'einBeispiel'};

    sub parse_form {
       my %input;
       my @names = $query->param;
       foreach (@names){
          $input{$_} = $query->param($_);
       }
       return %input;
    }

    Gruß Frank

    1. hi,

      Ich benutze gern eine der beiden folgen Varianten. Mein 1. parse_form erzeugt für jeden übergebenen Parameter eine Variable mit dem entsprechenden Namen und dem Wert. Das funktioniert für Skalare ebenso wie für Arrays, allerdings nicht mit "use strict", da Du im Script Variablen benutzt, die nicht mit 'my' erzeugt wurden.

      Hast Du im Formular folgende Zeile
      <input type="text" name="einBeispiel" value="blabla">,
      dann steht nach Aufruf von parse_form in der Variablen $einBeispiel der String "blabla" und Du kannst ihn "einfach benutzen":

      use CGI;
      &parse_form();
      print $einBeispiel;

      für was brauch ich print...?
      In meinem fall handelt es sich um ein login user/password formular.
      Die daten im formular sind folgend:
      <input type="username" name="username" size="15" maxlength="40">
      <input type="password" name="password" size="15" maxlength="14">
      <input type="hidden" name="function" value="post">
      <input type="hidden" name="text" value="vonhierkommich">
      Also ich habs versucht mit beiden beispielen ,aber apache
      sendet mir nur error 500.
      ich habs so
      sub parse_form {
         use CGI;
         my %input;
         my $query;
         my @names = $query->param;
         foreach (@names){
            $input{$_} = $query->param($_);
         }
         return %input;
      }

      versucht.
      da fehlt noch was (vielleicht ein value?) vermute ich mal.
      Mein error log meint dies:
      Can't call method "param" on an undefined value at logintest.cgi line 133.

      was soll query bedeuten? ohne "my $query;" gehts auch ned.

      use CGI;
      my %input = parse_form();
      print $input{'einBeispiel'};

      sub parse_form {
         my %input;
         my @names = $query->param;
         foreach (@names){
            $input{$_} = $query->param($_);
         }
         return %input;
      }

      Gruss vom
      Alain

      1. use Mosche;

        use CGI;
           my $query;

        my $query = new CGI;

        my @names = $query->param;

        use Tschoe qw(Matti);

        --
          Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
        1. hi,
          ich habs versucht aber leider nach wie vor error 500 mit der message

          Global symbol "@name" requires explicit package name at logintest.cgi line 134
          Global symbol "$query" requires explicit package name at logintest.cgi line 135

          müssen die einzelnen name->values auch im cgi geschrieben werden?

          use CGI;
             my $query;

          my $query = new CGI;

          my @names = $query->param;

          Hab da ehrlich gesagt etwas probleme mit der neuen use CGI methode.
          Gruss
          Alain

          1. Hallo Alain.

            Global symbol "@name" requires explicit package name at logintest.cgi line 134
            Global symbol "$query" requires explicit package name at logintest.cgi line 135

            Das dürfte daran liegen, dass du hier:

            my $query;
                  my $query = new CGI;

            $query zweimal als lokal deklariert hast. Lasse die erste Anweisung einfach weg, sie ist überflüssig.

            Weiterhin (wenn es sich nicht um einen Tippfehler handelt) ist

            my @names = $query->param;

            nicht identisch mit @name.

            Grüße
            Siechfred

            1. Hallo,

              $query zweimal als lokal deklariert hast. Lasse die erste Anweisung einfach weg, sie ist überflüssig.

              Weiterhin (wenn es sich nicht um einen Tippfehler handelt) ist

              my @names = $query->param;

              nicht identisch mit @name.

              leider nein,es handelt sich weder um ein tippfehler noch um doppelte einträge.
              Der code sieht zur zeit so:
              sub parse_form {
                 use CGI;
                 my %input;
                 my $query = new CGI;
                 my @names = $query->param;
                 foreach (@names){
                    $input{$_} = $query->param($_);
                 }
                 return %input;
              }

              aus.Mir scheint als ob da value fehlt?!
              Sollte der eintrag nicht in etwa so
              my @values = $query->param($name);
              lauten?
              error meldung vom server:
              Global symbol "$query" requires explicit package name at logintest.cgi line 135.,
              Global symbol "@name" requires explicit package name at logintest.cgi line 134

              Gruss
              vom Alain

              1. Hallo nochma,
                ich hatte das script am falschen ort abgespeichert bzw. das falsche hochgeladen.
                Es geht so - gut :)
                Eine frage dazu nun,ist diese art parsen sicherer als vorher?

                Der code sieht zur zeit so:
                sub parse_form {
                   use CGI;
                   my %input;
                   my $query = new CGI;
                   my @names = $query->param;
                   foreach (@names){
                      $input{$_} = $query->param($_);
                   }
                   return %input;
                }

                Gruss
                vom Alain

                1. Moin auch.

                  Eine frage dazu nun,ist diese art parsen sicherer als vorher?

                  Was heißt sicherer? Die Parameter kommen sicher im Script an. Und Du kannst Dich darauf verlassen (so Dein Provider aktuelle Versionen der Module bereitstellt), daß Du fehlerfreien Code benutzt. Nun ist es Deine Aufgabe, dafür zu sorgen, daß Eingaben böswiller User durch Schwachstellen in Deinem Script nicht Schaden anrichten. Einen guten Artikel dazu findes Du unter http://www.xwolf.de/artikel/cgisec.shtml.

                  &parse_form();
                  print $einBeispiel;

                  für was brauch ich print...?

                  Das war doch nur ein Beispiel für die Verwendung der Variablen ;)

                  Der code sieht zur zeit so:
                  sub parse_form {
                     use CGI;
                     my %input;
                     my $query = new CGI;
                     my @names = $query->param;
                     foreach (@names){
                        $input{$_} = $query->param($_);
                     }
                     return %input;
                  }

                  Das 'use CGI;' würde ich übrigens an den Anfang des Scripts stellen, gleich hinter 'use CGI::Carp qw(fatalsToBrowser);'. Und sorry: das 'my $query = new CGI;' hatte ich in meinen Beispielen ganz vergessen. Dank der Hilfe der anderen gehts ja nun.

                  Gruß Frank

                  1. Hallo,

                    Was heißt sicherer? Die Parameter kommen sicher im Script an.

                    naja ob das genug ist?
                    Kann man grundsätzlich davon ausgehen,das ein cgi perl skript sicher vor böswilliger
                    manipulation ist,wenn
                    man taint modus und use strict benutzt,vorausgesetzt es läuft so natürlich?
                    naja den einen code hab ich mal drinnen gelassen:
                    if ($ENV{'CONTENT_LENGTH'} > 200)
                    {
                    die("cgi script is overloadet try it later again\n");
                    }

                    Gruss vom Alain

                    --
                    ..."Zwei Dinge sind unendlich, das Universum und die menschliche Dummheit, aber bei dem Universum bin ich mir noch nicht ganz sicher." (Albert Einstein)
    2. Mit keinen Änderungen ist dieses "Verfahren" auch mit "use strict" nutzbar. Du mußt Dir einen Hash mit 'my' anlegen, die Namen der Formularfelder werden als Keys verwendet. Der Zugriff erfolgt dann wie gehabt:

      use CGI;
      my %input = parse_form();
      print $input{'einBeispiel'};

      sub parse_form {
         my %input;
         my @names = $query->param;
         foreach (@names){
            $input{$_} = $query->param($_);
         }
         return %input;
      }

      Was ist eigentlich der Vorteil davon eine zusätzliche Variabel anzulegen von einem Wert, der sowieso schon zu verfügung steht?

      es reicht voll und ganz aus:

      use CGI;
      print CGI::param('einBeispiel');

      parse_form ist absolut überflüssig.

      Struppi.

      1. Hallo Struppi.

        Was ist eigentlich der Vorteil davon eine zusätzliche Variabel anzulegen von einem Wert, der sowieso schon zu verfügung steht?

        Naja, ich vermute, dass hier der Gedanke des Taintmodus dahinter stecken könnte.

        print CGI::param('einBeispiel');

        Allerdings werden (so sagen mir meine bescheidenen Englischkenntnisse) Argumente für print-Anweisungen nicht als "tainted" behandelt und somit nicht geprüft:

        http://www.perldoc.com/perl5.8.0/pod/perlsec.html#DESCRIPTION, nach dem 4. Absatz.

        parse_form ist absolut überflüssig.

        Das sehe ich grundsätzlich nicht so. Nach meiner Meinung sollte jede Ausgabe von außen auf ihre Sicherheit geprüft werden (was zugegebenermaßen im Ausgangscode nicht gemacht wird). Vor diesem Hintergrund erscheint mir eine Subroutine, welche die Parameter auf Verträglichkeit prüft und die geprüften Parameter als Hash auswirft, durchaus sinnvoll, denn auch eine print-Anweisung kann mit entsprechenden Argumenten versehen "böse" sein. Um Missverständnissen vorzubeugen, die Subroutine parse_form() ist im speziell geposteten Code überflüssig, da sie das nicht tut, was ich eben schrieb. Allerdings halte ich deinen Vorschlag weiter oben ohne weiteres "Drumherum" ebenso für nicht gut.

        Grüße
        Siechfred

        1. use Mosche;

          [...] eine print-Anweisung kann mit entsprechenden Argumenten versehen "böse" sein.

          Könntest du mir hier bitte ein Beispiel geben?

          use Tschoe qw(Matti);

          --
            Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
          1. Hallo Matti.

            [...] eine print-Anweisung kann mit entsprechenden Argumenten versehen "böse" sein.
            Könntest du mir hier bitte ein Beispiel geben?

            Ich wusste, dass die Frage kommt :-)

            Gemeint habe ich folgenden Fall. Angenommen, du hättest eine Textarea, in die du HTML-Code eingibst. Würdest du in diese Textarea das Folgende eintippen:

            <html>
            <body>
            <script type="text/javascript">
            <!--
              alert("Ein bisschen Javascript");
            -->
            </script>
            </body>
            </html>

            und als Formularaktion an ein Script übergeben, das wie folgt aussähe:

            #!/usr/bin/perl
            use CGI;
            print "Content-Type: text/html\n\n";
            print CGI::param('text');

            würde der oben stehende JS-Code ausgeführt werden. Deshalb meine Aussage, dass ich Parameter, die einem Script übergeben werden, grundsätzlich nicht ungeprüft ausgeben lassen würde. Ich erinnere in diesem Zusammenhang nur an den allseits bekannten Gästebuchterminator.

            Grüße
            Siechfred

            1. use Mosche;

              Gemeint habe ich folgenden Fall. Angenommen, du hättest eine Textarea, in die du HTML-Code eingibst. Würdest du in diese Textarea das Folgende eintippen:
              [...]

              Tatsächlich. Auf die Idee, so ein Stück (Perl-)Code zu schreiben, dass _so_ Ausgaben ungefiltert durchlässt, bin/wäre ich gar nicht gekommen :-).

              use Tschoe qw(Matti);

              --
                Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
  3. use Mosche;

    Ich füge mal meinen code unten hin zur einsicht:
    my %input = parse_form();
    sub parse_form { [...] }

    Ich würde auf jeden Fall CGI verwenden. Spätestens, wenn du auch Dateien hochladen willst oder so, dann wird die Benutzung von CGI.pm alles ziemlich erleichtern. CGI.pm wird nämlich extra für sowas geschrieben und auch weiterentwickelt.

    Für die vorhandenen Scripte (wenn du sie den ändern willst) schreib in parse_form einen Wrapper um CGI.pm, der die dortigen Werte in deinen Hash einliest. Für _neue_ Scripte greife am Besten gleich auf CGI zu. Durch das Kopieren in den Hash geht unnötig Zeit verloren (obwohl das bei Perl meist nicht soviel ausmacht).

    use Tschoe qw(Matti);

    --
      Anyone who quotes me in their sig is an idiot. -- Rusty Russell.