CGI-skripty, které jsme si ukázali v posledním díle 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íváme na to, jak může nějaká data poslat prohlížeč serveru.
Existují dvě 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%20NovakV 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:
<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">
.
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 metodu 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říklad na
souřadnicích (x,y)=(10,50), na server se odešle požadavek
http://www.nekde.cz/imagemap?10,50
.
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 '&'.
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=47Vidí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í tři možnosti:
<ISINDEX>
nebo
souřadnice na klikací mapě).
QUERY_STRING
.
Tento způsob je typický pro předávání dat z formuláře odeslaného metodou
GET.
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ějž přišel požadavek |
REMOTE_ADDR | IP-adresa počítače, z nějž 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, který
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í' fi 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 guru, nežli pro "normálního člověka".
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. Pokud tedy nějaký "chytrák" zavolá náš skript pomocí následujícího URL:
http://server/cgi-bin/obsluha.cgi?;whoDojde 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. Pokud použijeme např. URL:
http://server/cgi-bin/obsluha.cgi?;cat</etc/passwdVrá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í telnetu 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 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 pro 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 -- nyní již znáte princip jejich práce a způsob předávání parametrů.
V příštích pokračováních seriálu se podíváme na různé druhy vstupních polí, které lze používat ve webovských formulářích.