P°edßvßnφ parametr∙ pomocφ rozhranφ CGI
Ji°φ Kosek ml.
CGI skripty, kterΘ jsme si ukßzali v poslednφm dφlu naÜeho serißlu, byly velmi jednoduchΘ -- zejmΘna proto, ₧e ke svΘ Φinnosti nepot°ebovaly ₧ßdnΘ informace od u₧ivatele. To vÜak nenφ p°φliÜ typick² p°φklad. Obvykle slou₧φ CGI skripty jako rozhranφ pro prßci s r∙zn²mi databßzemi. U₧ivatel m∙₧e nap°φklad zadat klφΦovß slova, kterß ho zajφmajφ. KlφΦovß slova se p°edajφ CGI skriptu a ten jako sv∙j v²sledek m∙₧e vygenerovat seznam vÜech Φlßnk∙ z databßze, kterΘ obsahujφ zadanß klφΦovß slova.
Z minula ji₧ vφme, ₧e parametry nejprve p°edß prohlφ₧eΦ serveru a ten je pak pomocφ rozhranφ CGI p°edß skriptu. Nejprve se tedy podφvejme na to, jak m∙₧e n∞jakß data poslat prohlφ₧eΦ serveru.
Existujφ 2 metody, jak p°enos dat uskuteΦnit. Prvnφ se jmenuje GET a slou₧φ pro p°enos kratÜφch informacφ. Pro p°enos v∞tÜφho mno₧stvφ dat pak slou₧φ metoda POST.
P°i pou₧itφ metody GET se vÜechny p°edßvanΘ informace p°ipojφ jako dotaz za otaznφk na konec URL, kterΘ ukazuje na CGI skript. V dotazu je pot°eba provΘst drobnΘ ·pravy: vÜechny mezery se nahradφ znakem "+" a znaky se specißlnφm v²znamem se nahradφ sekvencφ znak∙ "%xx", kde xx je hexadecimßlnφ k≤d znaku. Nap°φklad lomφtko se p°evede na sekvenci "%2F".
Pokud tedy chceme skriptu pokus.cgi jako parametr p°edat jmΘno "Jan Novak", m∙₧eme pou₧φt jedno z nßsledujφcφch URL:
http://server/cgi-bin/pokus.cgi?Jan+Novak
http://server/cgi-bin/pokus.cgi?Jan%20Novak
V obou dvou p°φpadech jsme museli p°ek≤dovat mezeru tak, aby URL tvo°ilo jeden dlouh² nep°eruÜen² °et∞zec.
TakovΘto zadßvßnφ parametr∙ vÜak nenφ pro u₧ivatele zrovna pohodlnΘ. NaÜt∞stφ existuje n∞kolik u₧ivatelsky p°φjemn∞jÜφch zp∙sob∙, jak p°im∞t prohlφ₧eΦ k vygenerovßnφ pot°ebnΘho URL s parametry:
- Strßnka obsahuje ve svΘm zßhlavφ tag <ISINDEX>. V tomto p°φpad∞ si prohlφ₧eΦ od u₧ivatele vy₧ßdß zadßnφ textu do vstupnφho pole. Obsah pole zak≤duje podle vÜech pravidel a metodou GET jej odeÜle skriptu urΦenΘmu pomocφ <BASE HREF="URL-skriptu">.
- U obrßzku, kter² je souΦasn∞ odkazem, pou₧ijeme atribut ISMAP. Takto p°ipraven² obrßzek pak slou₧φ jako klikacφ mapa, kterou obsluhuje server. Pokud n∞kam do obrßzku klikneme myÜφ, odeÜlou se metodou GET na server sou°adnice kliknutφ. Na jejich zßklad∞ server obvykle vrßtφ n∞jakou strßnku. Dnes se tento zp∙sob ji₧ p°φliÜ nevyu₧φvß, proto₧e klientskΘ klikacφ mapy jsou mnohem efektivn∞jÜφ. I p°esto malß ukßzka:
<A HREF="http://www.nekde.cz/imagemap">
<IMG SRC="mapa.gif" ISMAP></A>
Pokud u₧ivatel klikne na obrßzek mapa.gif nap°. na sou°adnicφch (x,y)=(10,50), na server se odeÜle po₧adavek http://www.nekde.cz/imagemap?10,50.
- Nejpou₧φvan∞jÜφ metodou je za°azenφ formulß°e (element FORM) na strßnku. U formulß°e musφme specifikovat p°enosovou metodu GET pomocφ atributu METHOD=GET. Formulß° m∙₧e obsahovat vstupnφ pole n∞kolika typ∙. ┌daje zadanΘ do t∞chto vstupnφch polφ se p°ed odeslßnφm zak≤dujφ, p°i°adφ se jmΘnu vstupnφho pole a navzßjem se odd∞lφ znakem "&".
Pokud chceme pro p°edßnφ dat pou₧φt metodu POST, musφme na strßnce op∞t pou₧φt formulß°, ale jako metodu je t°eba uvΘst POST. Data se k≤dujφ stejn²m zp∙sobem jako v metod∞ GET, ale pro jejich odeslßnφ se vytvo°φ zvlßÜtnφ datovΘ spojenφ mezi prohlφ₧eΦem a serverem. To umo₧≥uje p°enßÜet v∞tÜφ objemy dat, ne₧ p°edstavuje p°idßnφ parametr∙ na konec URL.
Zp∙sob zak≤dovßnφ ·daj∙ z formulß°e si p°edvedeme na malΘ ukßzce. P°edpoklßdejme nßÜ znßm² formulß° z p°edchozφch dφl∙:
<FORM ACTION="http://server/cgi-bin/obsluha.cgi" METHOD=GET>
JmΘno: <INPUT TYPE=TEXT NAME=jmeno><BR>
V∞k: <INPUT TYPE=TEXT NAME=vek><BR>
<INPUT TYPE=SUBMIT VALUE="Odeslßnφ formulß°e">
</FORM>
Pokud u₧ivatel vyplnφ jako jmΘno "Pavel Severa" a jako v∞k "47", prohlφ₧eΦ po stisknutφ tlaΦφtka Odeslßnφ formulß°e vygeneruje nßsledujφcφ po₧adavek:
http://server/cgi-bin/obsluha.cgi?jmeno=Pavel+Severa&vek=47
Vidφme, ₧e obsah jednotliv²ch polφ je identifikovßn sv²m jmΘnem a pole jsou odd∞lena znakem "&".
U₧ vφme, jak m∙₧e prohlφ₧eΦ poslat data na server. Vra¥me se tedy k otßzce, jak server p°edß data naÜemu skriptu. Rozhranφ CGI nßm nabφzφ 3 mo₧nosti:
1. Data jsou skriptu p°edßna jako parametry na p°φkazovΘ °ßdce. To p°ichßzφ v ·vahu p°i p°edßvßnφ opravdu krßtkΘ informace pomocφ metody GET (klφΦovß slova zadanß pomocφ <ISINDEX> nebo sou°adnice na klikacφ map∞).
2. Data jsou p°edßna v prom∞nnΘ prost°edφ QUERY_STRING. Tento zp∙sob je typick² pro p°edßvßnφ dat z formulß°e odeslanΘho metodou GET.
3. Data jsou p°edßna na standardnφ vstup skriptu -- zp∙sob typick² pro p°edßnφ dat z formulß°e odeslanΘho metodou POST.
Krom∞ dat od u₧ivatele, kterß p°edß server skriptu, mßme k dispozici dalÜφ u₧iteΦnΘ informace ulo₧enΘ v prom∞nn²ch prost°edφ (viz tabulka 1).
Tab. 1: Prom∞nnΘ prost°edφ p°edßvanΘ skriptu rozhranφm CGI
Prom∞nnß | Obsah |
REQUEST_METHOD | UrΦuje zp∙sob p°edßvßnφ informacφ -- GET nebo POST |
QUERY_STRING | Obsahuje data p°enßÜenß metodou GET |
PATH_INFO | Cesta, kterß mß b²t zpracovßna skriptem; nejΦast∞ji jde o Φßst cesty v URL za jmΘnem skriptu |
PATH_TRANSLATED | Cesta ke stejnΘmu souboru jako PATH_INFO; v tomto p°φpad∞ vÜak byla cesta p°emapovßna podle konfigurace serveru |
CONTENT_TYPE | MIME typ dat zasφlan²ch metodou POST |
CONTENT_LENGTH | DΘlka dat zasφlan²ch metodou POST |
SCRIPT_NAME | URL prßv∞ provßd∞nΘho skriptu |
SERVER_NAME | JmΘno serveru |
SERVER_PORT | ╚φslo portu |
SERVER_SOFTWARE | JmΘno a verze programu pracujφcφho jako WWW server |
SERVER_PROTOCOL | JmΘno a verze protokolu, kter²m p°iÜel po₧adavek (typicky HTTP/1.0 nebo HTTP/1.1) |
GATEWAY_INTERFACE | OznaΦenφ a verze pou₧itΘho rozhranφ ke spuÜt∞nφ skriptu (typicky CGI/1.1) |
REMOTE_HOST | DomΘnovß adresa poΦφtaΦe, z n∞ho₧ p°iÜel po₧adavek |
REMOTE_ADDR | IP adresa poΦφtaΦe, z n∞ho₧ p°iÜel po₧adavek |
AUTH_TYPE | Zp∙sob pou₧itΘ autorizace u₧ivatele |
REMOTE_USER | V p°φpad∞, ₧e byl u₧ivatel autorizovßn, obsahuje tato prom∞nnß jeho jmΘno |
REMOTE_IDENT | Informace o identit∞ zφskanß zp∞tn²m dotazem u klienta; tuto vlastnost p°φliÜ mnoho server∙ nevyu₧φvß |
Nynφ u₧ toho vφme dost na to, abychom si ukßzali CGI skript, jen₧ bude zpracovßvat parametry zadanΘ u₧ivatelem. Pou₧ijeme nßÜ osv∞dΦen² p°φklad, kter² hodnotφ u₧ivatele podle jeho v∞ku. Zadßnφ ·daj∙ umo₧nφme u₧ivateli v²Üe uveden²m formulß°em. Skript, kter² vyhodnotφ ·daje na formulß°i, pojmenujeme obsluha.cgi.
#!/bin/sh
echo 'Content-type: text/html'
echo
echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">'
echo '<HTML>'
echo '<HEAD>'
echo '<TITLE>Obsluha formulß°e</TITLE>'
echo '</HEAD>'
echo '<BODY>'
echo '<H1>V²sledek obsluhy formulß°e</H1>'
eval `echo $QUERY_STRING | awk 'BEGIN{RS="&"} {printf "WWW_%s\n",$1}' `
WWW_jmeno=`echo $WWW_jmeno | tr "+" "\040"`
echo "$WWW_jmeno je"
if [ $WWW_vek -lt 10 ]; then
echo 'p∞knej mlφΦnßk'
elif [ $WWW_vek -lt 20 ]; then
echo 'teenager'
elif [ $WWW_vek -lt 60 ]; then
echo 'v nejlepÜφch letech'
elif [ $WWW_vek -lt 100 ]; then
echo 'je pravd∞podobn∞ prarodiΦ'
else
echo 'je n∞kde mezi stovkou a smrtφ'
echo '</BODY>'
echo '</HTML>'
CGI skript jsme op∞t zapsali v p°φkazovΘm interpretu sh. P°edem upozor≥uji, ₧e po vyzkouÜenφ skriptu je nejlepÜφ jej ihned smazat. NßÜ skript toti₧ nenφ zdaleka bezpeΦn², jak si za chvφli ukß₧eme.
Podφvejme se nynφ na skript troÜku podrobn∞ji. Prvnφ °ßdek obsahuje urΦenφ interpretu, kter² se na skript pou₧ije. Dßle pak generujeme HTTP hlaviΦku a kostru HTML strßnky.
Dva °ßdky na zaΦßtku t∞la strßnky jsou opravdu magickΘ. Prvnφ z nich pro ka₧dΘ pole formulß°e, jeho₧ hodnota je p°edßna v prom∞nnΘ QUERY_STRING, vytvo°φ prom∞nnou WWW_jmΘno-pole s obsahem p°φsluÜnΘho pole. To nßm usnadnφ dalÜφ prßci s p°edan²mi parametry. Druh² °ßdek v prom∞nnΘ WWW_jmeno (ta nese obsah vstupnφho pole jmeno) nahradφ vÜechny v²skyty znaku "+" mezerou (ASCII k≤d 40 v osmiΦkovΘ soustav∞).
Podmφnka [ $WWW_vek -lt n ] je spln∞na, pokud je prom∞nnß $WWW_vek menÜφ ne₧ n. N∞kolik vno°en²ch podmφnek zajistφ vytiÜt∞nφ p°φsluÜnΘho komentß°e podle v∞ku u₧ivatele.
Vidφme, ₧e tvorba skript∙ cestou p°φkazovΘho interpretu je urΦena spφÜe pro unixovΘho specialistu, ne₧li pro "normßlnφho Φlov∞ka".
BezpeΦnost a CGI skripty
Pro psanφ CGI skript∙ se nejΦast∞ji pou₧φvajφ interpretovanΘ jazyky jako Bourne shell (sh) nebo Perl. To vÜak p°inßÜφ velkß bezpeΦnostnφ rizika. Ukß₧eme si zde bezpeΦnostnφ dφru v naÜem skriptu.
Pokud n∞kdo bude chtφt nßÜ skript zneu₧φt pro zjiÜt∞nφ d∙le₧it²ch informacφ o systΘmu, m∙₧e vyu₧φt n∞kterΘ mΘn∞ znßmΘ vlastnosti interpretu sh. Mezi n∞ pat°φ i to, ₧e na jednΘ °ßdce lze p°φkazy odd∞lovat pomocφ st°ednφku -- to mß v²znam, pokud nap°. n∞jak² "chytrßk" zavolß nßÜ skript pomocφ nßsledujφcφho URL:
http://server/cgi-bin/obsluha.cgi?;who
Nßsledkem tohoto p°φkazu dojde v CGI skriptu k expanzi p°φkazu echo $QUERY_STRING na echo ;who. V²sledkem je, ₧e na v²stup skriptu se zapφÜe prßzdnß °ßdka (p°φkaz echo) a v²sledek programu who. Zcela kdokoliv tak m∙₧e zjistit, kdo v danou chvφli pracuje na serveru. Mφsto p°φkazu who m∙₧eme pou₧φt libovoln² jin² p°φkaz -- nap°. nßsledujφcφ URL:
http://server/cgi-bin/obsluha.cgi?;cat</etc/passwd
Vrßtφ se nßm strßnka, kterß na svΘm zaΦßtku bude obsahovat v²pis informacφ o vÜech u₧ivatelφch systΘmu. Z tohoto v²pisu lze zjistit u₧ivatele, kte°φ heslo nemajφ nastaveno, a u t∞ch ostatnφch lze pom∞rn∞ snadno jejich heslo rozÜifrovat. Kdokoliv se pak pomocφ protokolu Telnet m∙₧e p°ipojit na server a provßd∞t tam tΘm∞° cokoliv.
Pokud tedy chceme vytvß°et bezpeΦnΘ skripty v interpretovan²ch jazycφch, musφme v₧dy p°φchozφ data zkontrolovat a p°ed jejich zpracovßnφm z nich eliminovat vÜechny nebezpeΦnΘ znaky (jako je st°ednφk).
OÜet°it vÜechny nebezpeΦnΘ kombinace vstupnφch parametr∙ nenφ vÜak v∙bec jednoduchΘ a je celkem pravd∞podobnΘ, ₧e na n∞jakou mo₧nost zapomeneme. Je proto lepÜφ CGI skripty psßt v jazycφch, ve kter²ch je nutno program p°ed spuÜt∞nφm p°elo₧it do spustitelnΘ formy. V t∞chto jazycφch (C, C++, Java apod.) je pak v²Üe zmφn∞nΘ nebezpeΦφ obelst∞nφ skriptu do znaΦnΘ mφry eliminovßno.
Vid∞li jsme, ₧e CGI skripty jsou jako ohe≥ -- dobr² sluha, ale Üpatn² pßn. V serißlu se budeme p°φÜt∞ zab²vat p°edevÜφm skriptovacφmi jazyky, kterΘ se vklßdajφ p°φmo do HTML strßnky, jako je PHP a ASP. Prßce s nimi je jednoduÜÜφ a v∞tÜinou i efektivn∞jÜφ. Pro specißlnφ aplikace vÜak m∙₧e b²t v²hodnΘ pou₧φt CGI skripty -- a nynφ ji₧ znßte princip jejich prßce a zp∙sob p°edßvßnφ parametr∙.