CGI (Common Gateway Interface) - možnost zavést dynamické www-stránky, - protokol popisující, jak bude server zpracovávat požadavky klienta - CGI skript se v prohlížeči nezobrazí, zobrazí se jen jeho výstup. Motivace: - počítadla přístupů (čehokoliv), - vyhledávací stroje (Alta Vista, Seznam, Yahoo...), - skripty zobrazující reklamní bannery. - kniha hostů ... Jak vypadá CGI skript? Jako normální spustitelný (či interpretovatelný) soubor. Lze jej napsat v libovolném jazyku, pro nějž máme vhodný interpret. Z tohoto důvodu jsou nejrozšířenější právě vysoce nebezpečné skripty psané v shellu, jinak se však používají i skripty psané v Pearlu, či programy napsané v C/C++. Slyšel jsem i o speciálně upraveném interpretu Prologu či Haskellu, v praxi jsem však na skript psaný v neprocedurálním jazyku nenarazil. U skriptu je však potřeba dodržet určitá pravidla: 1. Je-li skript interpretovaný (shell skript), musí jeho první řádek vypadat takto: #! tedy např.: #!/bin/bash Začíná-li skript jinak, považuje se za spustitelný soubor a server se jej pokusí spustit, což obvykle vede k chybové hlášce. 2. Omezení vyplývající z WWW protokolu: Každý výstup musí být napřed řádně uveden co do obsahu: Content-type: typů dat je mnoho a mnoho z jejich označení lze je zjistit kupř. v NetScape navigatoru - menu Options/Helpers, kde si člověk vybírá, čím si chce soubor kterého typu prohlížet. Nejčastější typy: text/html, text/plain, application/zip. Příklad skriptu: 1. příklad - vypsat hlášku "Hallo, world!". Pro řešení jsem zvolil (tradiční) prostředí shellu: #!/bin/bash echo 'Content-type: text/plain' echo echo 'Hallo, world!' Pro ilustraci významu položky Content-type - tentýž příklad: #!/bin/bash echo 'Content-type: text/html' echo echo '' echo 'Hallo, world!' echo '' Jak server přimět, aby můj skript spustil a co potom může dělat? Téměř každý server je nastaven jinak a tudíž na každém stroji jsou přesvědčovací pravidla jiná. Obecně však má mít CGI skript koncovku .cgi (na Artaxu), nebo musí být v adresáři cgi-bin (na ss1000). Skript je potom spuštěn (obvykle) s právy uživatele s UID=-1 (65535), někde se však také rozběhne s Vašimi právy (Artax před krachem disku). Z toho vyplývají tato omezení: Skript smí zapisovat pouze do souborů, do nichž smí zapisovat každý, což je poněkud třaskavá směs. Stejně tak těžko (ještě mnohem hůře) se mu bude nějaký soubor vytvářet. Každý, kdo přidělí k adresáři se svými www stránkami komukoliv práva w, je SEBEVRAH!!! Proměnné prostředí v CGI: Mohou být definovány různě, obvyklé a zajímavé jsou tyto: $REQUEST_METHOD - bude níže "$QUERY_STRING" - bude níže $REMOTE_HOST - IP adresa stroje, ze kterého někdo přistupuje $REMOTE_ADDR - URL stroje, ze kterého... - mnohdy nebývá, je třeba užít nslookup. Jejich úplný výpis (skoro u všech člověk uhodne, co obsahují), získáme například následujícím skriptem: #!/bin/bash echo 'Content-type: text/html' echo set Zastavíme se blíže u proměnné QUERY_STRING. Do této proměnné se zapíše všechno, co napíšete v adrese (při volání skriptu) za otazník, který dáte na konec jména stránky se skriptem. Příklad: http://linux.kolej.mff.cuni.cz/skript.cgi?nazdar nastaví proměnnou QUERY_STRING=nazdar Vstup a výstup dat Kdyby CGI skriptům nešlo předat data (argumenty), byly by celkem k ničemu. Lze jim tedy předložit na vstup určitá data (viz kupř. vyhledavače). Toho dosáhneme obvykle odesláním HTML formuláře. Příklad:
Napište mi něco:
Data lze zaslat dvěma způsoby (dvěma metodami). GET a POST. Výše uvedený příklad zasílá metodou get. Tato metoda zasílanými daty naplní proměnnou QUERY_STRING. V našem příkladu tedy provede totéž, jako napsání knihovnik.cgi?pripominky=implicitni+text. Jak je vidět, při přenosu podle WWW protokolu se různé znaky šifrují (např. mezera se změní v plus, jiné znaky se změní ve vlnku a hexadecimálně zapsaná ASCII hodnota...). Metoda POST předá argumenty skriptu na stdin. Problémy se skripty Skripty jsou obecně velmi nebezpečné, zvláště jsou-li psány jako shell-skripty. Jako příklad uveďme jednu z nejhorších a nejméně nápadných chyb. Autor si v dobré víře chtěl napsat primitivní kalkulačku, kterou však ohrozil bezpečnost posádky serveru: #!/bin/bash echo Content-type: text/plain echo read a b=convert $a echo `expr $b` Tento skript na první pohled vyčíslí numerický výraz zadaný jako argument, ve skutečnosti je však nástroj ďáblův. Kupř. zadá-li se mu (metodou post) řetězec "cat+/etc/passwd", divné věci se budou dít. Má-li někdo /etc/passwd, může zkusit zaútočit na kohokoliv a údajně se v posádce vždycky najde někdo se slabším heslem. Popř. zdá-li se někomu hrozba stažení /etc/passwd nicotná, postačí, aby se skript spouštěl s právy vlastníka a argumenty "cat+mail/*" by Vás připravily o soukromí. Tipy & triky: Kromě Content-type lze předávat ještě jiné informace. Například: Pragma: no-cache - zařídí, aby dokument, v jehož hlavičce se objeví tato hláška, browser neukládal do cache, ale udržoval jej přímo v paměti. Status: 200 OK 204 No Response 301 Document Moved 401 Unauthorized 403 Forbidden 404 Not Found 500 Internal Server Error 501 Not Implemented - říkají klientovi, co se na našem serveru stalo za karambol. Status: 200 OK oznamuje, že je všechno v pořádku a zbytek stránky bude následovat. Status: 204 No Response říká, že na daný dotaz nadále odpovídat nebudeme (užitečné, pokud uživatel zadal špatné argumenty). Status: 404 Not Found je vyvolán neexistencí žádaného dokumentu Status: 500 Internal Server Error nejhorší z uvedených hlášek, každý autor skriptů zajásá, když ji vidí. Mezi posílání argumentů metodou GET a POST je ještě jeden závažný rozdíl. Práce s argumenty zaslanými metodou POST sice vypadá jako jednodušší, ale zato je mnohem méně bezpečná. Přistoupí-li kdokoliv na jakoukoliv www-stránku, vše, co napíše do políčka adresy (tedy i to za otazníkem), bude zapsáno do logu. Data předávaná metodou POST se však NEZAPÍŠÍ a nezapíše-li si je člověk pomocí skriptu sám, nikdo se nedozví, kdo tam jaké požadavky posílá. Větší příklad CGI skriptu: #!/bin/bash ... nslookup $REMOTE_HOST|grep ^Name:|read nic a if[ `echo $a|grep $JMENO|wc -l` -gt 0 ] then echo Status: 404 Not Found else if[ -z "$QUERY_STRING" ] then convert $QUERY_STRING >> pripominky.txt echo '

' >> pripominky.txt fi echo Content-type: text/html echo echo '' echo Nemám rád $JMENO'!!!' echo '

' echo 'A co vy?' echo '' echo '' echo '
' echo '

A tohle jste mi již napsali:' cat pripominky.txt echo '' Chcete-li zjistit vice, zkuste napsat svemu browseru toto: http://www.altavista.com/cgi-bin/query?pg=aq&kl=XX&r=&search=Search&q=CGI+and+tutorial&d0=&d1=