Rund um CGI - eine Einführung
Der Inhalt dieser Seite und vieles mehr ist eingeflossen in
CGI - kurz & gut, 2.Auflage
(O'Reilly 2003, ISBN 3-89721-244-7).
CGI ist die Abkürzung für "Common Gateway Interface". Es ist
ein Satz von Regeln (ein "Protokoll") für die Kommunikation
zwischen einem Webserver und externen Programmen ("Gateways"). Externe
Programme werden auf Websites zum Beispiel genutzt, um
- Webserver-Ausgaben dynamisch zu erzeugen, z.B. HTML, Bilder, PDF, etc.
- Formulare zu verarbeiten
- Suchmaschinen, Shopping Carts, Gästebücher, Besucher-Zähler, Chatrooms, etc. zu implementieren
kurz: um etwas zu erreichen, was mit statischen HTML-Seiten nicht zu machen ist.
CGI wurde für den "Ur-Webserver" NCSA HTTPd entwickelt. Bis heute
existiert nur ein RFC-Draft (eine Diskussionsgrundlage für einen
Internet-Standard) dafür, womit es eins der wenigen Dinge im
Internet sein dürfte, die nicht per RFC standardisiert sind.
[Zum Inhaltsverzeichnis]
Ein Beispiel: Ein Benutzer gibt den URL
"http://host/htbin/helpgate/help" in seinen Browser ein, und erhält
eine HTML-Seite mit Online-Hilfe zum Betriebssystem OpenVMS.
Was geschieht hier im Detail?
- Der Benutzer gibt den URL "http://host/htbin/helpgate/help" in seinen Browser ein.
- Der Browser baut eine TCP/IP-Verbindung zum Rechners "host" auf
(hier zu Port 80) und schickt eine Anfrage nach dem relativen URL "/htbin/helpgate/help".
- Der Webserver weiß (durch seine Konfiguration), daß das virtuelle Verzeichnis
"/htbin" CGI-Programme enthält und daß es dem physikalischen VMS-Verzeichnis
WWW_ROOT:[BIN] entspricht, und ruft das dort befindliche Kommandozeilen-Skript
HELPGATE.COM auf, wobei die übermittelten Daten (z.B. das angehängte "/help")
und weitere Informationen übergeben werden.
- HELPGATE.COM verarbeitet die Daten und gibt seinerseits eine Antwort
an den Webserver.
- Der Webserver ergänzt evtl. die Antwort und sendet sie an den Browser
zurück.
- Der Browser interpretiert die Antwort und stellt sie dar.
Das Protokoll in Punkt 2. und 5. ist HTTP (HyperText Transfer Protocol),
Punkt 3. und 4. werden vom CGI-Protokoll abgedeckt.
Die Datenübergabe zum CGI-Programm findet in (im RFC-Draft so genannten)
"Meta-Variablen" statt, deren Implementation i.d.R. Environment-Variablen
darstellen. Ausserdem können Daten über den Standard-Input-Kanal des CGI-Programms
übergeben werden, sowie in seltenen Fällen auch über dessen Kommandozeile.
Die Ausgabe des CGI-Programms findet über dessen Standard-Output-Kanal statt.
Daraus folgt, daß als Programmiersprachen für CGI alle Sprachen geeignet sind,
die mindestens mit diesen drei Mechanismen (Meta-Variablen, Standard Input
und Output) umgehen können, also z.B. C, C++ und Pascal, aber auch Interpreter
(z.B. Perl, Python, Tcl), wenn der Webserver weiß, wie er mit Programmen für
den Interpreter umzugehen hat.
Beschäftigen wir uns nun mit all den Einzelteilen, die oben angesprochen wurden.
Dabei wird für die anfragende Seite der Verbindung statt "Browser" das
allgemeinere "Client" verwendet, da Anfragen auch durch Programme, über
Proxy-Gateways, usw. gestellt werden können.
[Zum Inhaltsverzeichnis]
URLs stellen ein Bezeichnungssystem für verteilt liegende Resourcen dar.
Sie werden auch URIs (Uniform Resource Identifiers) genannt, obwohl zwischen
den beiden Bezeichnungen ein feiner Unterschied besteht. Das Format für
einen absoluten URL im HTTP-Protokoll sieht so aus:
http://host[:port][path[?query]]
Teile in [ ] sind optional. Dabei gilt:
- host ist der Hostname oder die IP-Adresse des anzusprechenden
Rechners.
- Der Defaultwert für port ist 80.
- path ist der virtuelle, hierarchische Pfad zu der Resource
auf dem Rechner host.
"Virtuell" heisst dabei, daß dies kein physikalisch
vorhandener Pfad sein muß (die Übersetzung in einen solchen
leistet der Webserver); "hierarchisch" heisst, daß path
aus einer Folge von Unter-Pfaden besteht, die durch / getrennt werden.
Wenn path nicht benutzt wird, muß stattdessen
ein / als Trennzeichen eingesetzt werden.
- Das Format für den query-Anteil ist:
name=wert&name=wert...
oder
keyword+keyword...
Siehe unter "URL-Kodierung" und
"Kodierung von Formulardaten".
Bei einem relativen URL fehlt ein Teil des absoluten URL, z.B. "http://host".
[Zum Inhaltsverzeichnis]
Für den query-Teil einer HTTP-URL gelten folgende Richtlinien:
[Zum Inhaltsverzeichnis]
HTTP ist das Protokoll für die Kommunkation zwischen einem Client und einem
Webserver. Es ist ein zustandsloses Anfrage-/Antwort-Protokoll.
"Zustandslos" bedeutet hierbei, daß jedes Anfrage-/Antwort-Paar für
sich steht, und nicht im Zusammenhang mit vorherigen oder nachfolgenden Paaren.
Eine Anfrage besteht aus
Eine Antwort besteht aus
- einer Zeile mit der Protokollversion, einem Status-Code und einer
(optionalen) textuellen Beschreibung des Status, z.B.
HTTP/1.0 200 OK
- MIME-Kopfzeilen mit Meta- und Zusatz-Information
- einer Leerzeile
- i.d.R. einem Antwort-Rumpf
Kopfzeilen (d.h. alle Zeilen vor der Leerzeile) werden hierbei durch CR+LF
(ASCII-Code 13 und 10) abgeschlossen.
[Zum Inhaltsverzeichnis]
Das Problem: RFC 822 (die Grundlage für die Übertragung von Nachrichten im
Internet) definiert ein Format nur für 7-Bit-ASCII-Zeichen und maximal 1000
Zeichen/Zeile. Um diese Begrenzungen zu überwinden, wurde MIME definiert.
Eine MIME-Nachricht wird eingeleitet durch die Kopfzeile
MIME-Version: 1.0
Weitere MIME-Kopfzeilen spezifizieren den Typ und die Kodierung des
Nachrichten-Inhalts:
Content-Type: type/subtype [; parameter=value]
z.B. text/plain; charset=ISO-8859-1 oder image/gif
Content-Transfer-Encoding
mögliche Werte: 7bit, 8bit, binary, base64, quoted-printable
Die beiden übrigen Standard-MIME-Kopfzeilen sind
Content-ID
Content-Description
Andere, mit "Content-" beginnende Kopfzeilen werden vom Standard nicht abgedeckt
und dürfen vom Empfänger ignoriert werden.
MIME ermöglicht auch die Übertragung mehrteiliger Rümpfe, wobei die
Teil-Rümpfe verschiedene MIME-Typen haben können. Solche Nachrichten werden
spezifiziert durch
Content-Type: multipart/mixed; boundary="XYZ"
wobei "XYZ" ein (Teilrumpf-)Begrenzungsstring ist, der in der Nachricht sonst nicht
vorkommt. Die Einleitung für jeden Rumpf-Teil ist eine Zeile mit dem String
--XYZ
den Abschluß des letzten Rumpf-Teils bildet eine Zeile mit dem String
--XYZ--
Jeder Rumpfteil ist eine eigenständige Nachricht, deren Kopfzeilen aber
nur aus "Content-*"-Zeilen bestehen dürfen.
[Zum Inhaltsverzeichnis]
Die CGI-Spezifikation legt folgende Meta-Variablen zur Übermittlung von
Informationen zum CGI-Programm fest:
- REQUEST_METHOD
- enthält die Anfrage-Methode.
- QUERY_STRING
- enthält die Daten des query-Teils des URL genau so, wie die Anfrage
gestellt wurde, d.h. i.d.R. URL-kodiert.
- PATH_INFO
- enthält die Daten des path-Teils des Anfrage-URL, die dem Namen des
CGI-Programms folgen.
- PATH_TRANSLATED
- enthält eine versuchte Übersetzung von PATH_INFO in einen physikalischen
Pfad.
- CONTENT_TYPE
- enthält den MIME-Typ der Anfrage, falls diese Information in der Anfrage
übermittelt wurde.
- CONTENT_LENGTH
- enthält die Länge des Rumpfs in Bytes, falls ein Rumpf in der Anfrage
übermittelt wurde.
- SCRIPT_NAME
- enthält die Daten des path-Teils des Anfrage-URL bis zum Namen
des CGI-Programms.
- REMOTE_ADDR
- enthält die IP-Adresse des Clients.
- REMOTE_HOST
- enthält den Hostnamen zu REMOTE_ADDR. Da der Webserver diese Information
abfragen muß - was Performance kostet - ist REMOTE_HOST i.d.R. nicht
gesetzt.
- REMOTE_USER und AUTH_TYPE
- werden nur gesetzt und benutzt bei authentisierten Anfragen, d.h. bei Zugriff auf
geschützte Seiten.
- REMOTE_IDENT
- enthält den Inhalt einer "ident"-Abfrage beim Client. Da der Webserver
diese Information abfragen muß (Performance!), und viele Rechner
nicht auf "ident"-Anfragen antworten, wird dies selten benutzt.
- SERVER_NAME
- enthält den host-Teil des Anfrage-URL.
- SERVER_PORT
- enthält den port-Teil des Anfrage-URL, oder den tatsächlichen Port.
- SERVER_SOFTWARE
- enthält einen String, der die Webserver-Software charakterisiert.
- SERVER_PROTOCOL
- enthält die Protokollversion, mit der die Webserver-Software umgehen kann,
also i.d.R. "HTTP/1.0" oder "HTTP/1.1".
- GATEWAY_INTERFACE
- enthält die Protokollversion der CGI-Schnittstelle, i.d.R. "CGI/1.1".
- HTTP_*
- Diese Meta-Variablen enthalten zusätzliche HTTP-Kopfzeilen, die der
Client mitgeschickt hat, z.B.
- HTTP_ACCEPT
- HTTP_USER_AGENT
- HTTP_REFERER
- HTTP_X_FORWARDED_FOR
Dabei werden Bindestriche im Kopfzeilen-Namen durch Unterstriche ersetzt
(die Kopfzeile heißt also z.B. "X-Forwarded-For").
Je nach Webserver-Software werden außerdem weitere Variablen gesetzt,
z.B. von Apache u.a. DOCUMENT_URI, DOCUMENT_ROOT und FILEPATH_INFO.
[Zum Inhaltsverzeichnis]
Es existieren folgende Möglichkeiten, mit HTML-Tags Informationen in einer
Anfrage zu generieren:
- FORM
- leitet ein HTML-Formular ein, und besitzt folgende Attribute:
- ACTION
- enthält den URL des aufzurufenden CGI-Skripts
- METHOD
- Wert: GET oder POST
- ENCTYPE
- enthält den MIME-Typ der Anfrage.
Der Defaultwert ist application/x-www-form-urlencoded; einen Spezialfall
bildet multipart/form-data, der mit <INPUT TYPE=FILE>-Eingabefeldern
verwendet werden muß.
Siehe auch "HTML-Formulare".
- alle HTML-Tags, bei denen man einen URL angeben kann
- z.B. <A HREF=...>, <IMG SRC=...>
Diese generieren eine GET-Anfrage; Informationen werden also mit
einem führenden ? angehängt (siehe unter
"Kodierung von Formulardaten"). Zu beachten
ist, daß in diesem Fall im query-Teil der URL das Zeichen &
als & oder & geschrieben werden muss.
- ISINDEX
- Dies ist ein HTML-Tag, das im HEAD-Teil erlaubt ist, und kaum noch benutzt wird.
[Zum Inhaltsverzeichnis]
können folgende Tags enthalten, die Information generieren:
- INPUT
- ist ein allgemeines Eingabefeld, wird näher spezifiziert durch das
TYPE-Attribut, das folgende Werte haben kann:
- TEXT
- PASSWORD
- CHECKBOX
- RADIO
- IMAGE
- SUBMIT
- RESET
- HIDDEN
Weiterhin gibt es als TYPE-Wert FILE, der eine Erweiterung
des HTML-Standards ist; dieser darf nur nur mit <FORM METHOD=POST ENCTYPE=multipart/form-data>
verwendet werden.
- TEXTAREA
- spezifiziert ein (evtl. mehrzeiliges) Text-Eingabefeld
- SELECT und OPTION
- spezifizieren eine Auswahlliste von Optionen
[Zum Inhaltsverzeichnis]
Vor der Übertragung werden die Daten des Formulars kodiert:
[Zum Inhaltsverzeichnis]
Die Datenübergabe vom Webserver zum CGI-Programm findet statt:
- bei REQUEST_METHOD=GET über die Meta-Variable QUERY_STRING.
Bei ISINDEX-Anfragen kann (abhängig vom Webserver) die
Übergabe auch über die Kommandozeile erfolgen.
- bei REQUEST_METHOD=POST über Standard Input. Dabei ist folgendes zu beachten:
- Die Länge findet sich in der Meta-Variablen CONTENT_LENGTH.
- Eine Kennzeichnung des end-of-file kann fehlen; es dürfen also
höchstens CONTENT_LENGTH Bytes von Standard Input gelesen werden!
Für die gängigen CGI-Programmiersprachen existieren Erweiterungen,
welche eine Dekodierung der übergebenen Daten leisten (z.B. für Perl das Modul CGI.pm).
[Zum Inhaltsverzeichnis]
Die Ausgabe des CGI-Programs erfolgt nach Standard Output. Dabei sind zwei Fälle
zu unterscheiden:
- "Parsed Header"-Skripts
Die vom CGI-Programm generierten Kopfdaten werden vom Webserver ausgewertet;
das CGI-Programm muß keine vollständige HTTP-Nachricht erzeugen.
Das CGI-Programm generiert als Kopfzeilen
- CGI-Kopfzeilen (d.h. HTTP-Kopfzeilen, die vom Webserver ausgewertet werden)
- Status
Siehe die Liste der Status-Codes.
- Content-Type
muß vorhanden sein, wenn die Antwort einen Rumpf beinhaltet.
- Location
Umleitung auf eine andere Resource. Mögliche Werte sind
- ein relativer URL mit Status: 200
dieser wird vom Webserver ausgewertet, und die resultierende
Resource zurückgegeben
- ein absoluter URL mit Status: 30x (i.allg. 302)
dieser führt zur Weitergabe der Location-Kopfzeile
an den Client
Der CGI-RFC-Draft fordert, daß wenn diese Kopfzeile verwendet
wird, keine HTTP-Kopfzeilen in der Nachricht enthalten sein sollen.
- optional HTTP-Kopfzeilen
z.B. Expires
- "Non-Parsed Header"-Skripts (NPH)
Diese müssen komplette HTTP-Nachrichten ausgeben, die der Webserver unverändert
weitergibt. Der Kopf von HTTP-Nachrichten besteht aus
- 1. Zeile: HTTP-Statuszeile, z.B.
HTTP/1.0 200 OK
- HTTP-Kopfzeilen, z.B.
- Date, z.B.
Thu, 30 Mar 2000 08:25:00 GMT
- Server
Wie der Webserver beide Typen unterscheidet, ist implementationsabhängig.
Für Apache: Der Dateiname von NPH-Skripts beginnt mit "nph-".
Microsofts IIS behandelt alle Skripte als NPH-Skripte.
[Zum Inhaltsverzeichnis]
(Erwähnte ich schon, daß ich es zu aufwendig finde, mich an die reformierte Rechtschreibung zu gewöhnen?)
Ein CGI-Programm erlaubt es aller Welt, ein Programm (meist sogar mit
Parametern) auf dem Webserver auszuführen, i.d.R. ohne irgendwelche
Authentisierung oder Zugriffsschutz-Mechanismen. Daher ist Sicherheit
bei CGI-Programmen oberstes Gebot - für CGI-Programme sollte
immer das Akte-X-Motto gelten: Trust Noone! (und schon gar
nicht dem Client)
Im Einzelnen sollten folgende Punkte beachtet werden:
- Alle Eingaben, die vom Client kommen, müssen vor der Benutzung
geprüft werden. Einige Beispiele, wie ungeprüfte Daten
Schaden anrichten können:
- Werden Eingabedaten zur Generierung von Dateinamen benutzt,
kann z.B. durch Verwendung von '..' auf Pfade zugegriffen werden,
die der CGI-Programmierer nicht im Sinn hatte.
- Eingabedaten, die als Parameter für den Aufruf eines weiteren
Programms dienen sollen, stellen eine besondere Gefahr dar. Solch ein
Aufruf geschieht i.allg. über eine Shell, die gewisse Sonderzeichen
(z.B. Backticks oder Semikolons) interpretiert - was selten in der Absicht des
Programmierers liegt.
- Auch wenn ein HTML-Formular maximale Größen für
Eingaben enthält, darf sich ein CGI-Programm nicht darauf verlassen,
daß diese eingehalten werden - der CGI-URL kann jederzeit auch ohne das
Formular aufgerufen werden.
- Der Inhalt von <INPUT HIDDEN>-Feldern kann vom Client
beliebig verändert werden. Das CGI-Programm kann sich auf solche
Eingaben nicht verlassen.
Perl bietet speziell für CGI-Programme den sogenannten "Taint Mode",
in dem fast alle Daten, die von außerhalb des Programms kommen und
unbehandelt weiterverwendet werden, zu einem Fehlerabbruch führen.
- Datendateien (besonders solche mit sensitiven Daten), auf die das CGI-Programm
zugreift, sollten außerhalb des Zugriffs des Webservers liegen.
- Interpreter dürfen vom Webserver aus nicht per URL erreichbar sein.
Sonst besteht die Gefahr, daß dem Interpreter per Webzugriff ein
(einzeiliges) Fremd-Programm untergeschoben wird.
Weitere beachtenswerte Dinge:
- Der Webserver führt CGI-Programme i.d.R. unter einem wenig
privilegierten Account aus. Dies muß bei Dateizugriffen
berücksichtigt werden.
- Das aktuelle Verzeichnis wird von der CGI-Spezifikation nicht festgelegt!
Ein CGI-Programm sollte also keine relativen Datei-Pfade verwenden
(oder vorher ein chdir-Kommando ausführen).
[Zum Inhaltsverzeichnis]
Der Vollständigkeit halber folgt eine Liste aller Status-Codes, die von den
Standards HTTP/1.0 und HTTP/1.1 (gekennzeichnet durch *) definiert
werden.
1xx |
Information
100 * |
Continue |
101 * |
Switching Protocols |
|
2xx |
Erfolg
200 |
OK |
201 |
Created |
202 |
Accepted |
203 |
Non-Authoritative Information |
204 |
No Content |
205 * |
Reset Content |
206 * |
Partial Content |
|
3xx |
Umleitung
300 * |
Multiple Choices |
301 |
Moved Permanently |
302 |
Moved Temporarily / Found |
303 * |
See Other |
304 |
Not Modified |
305 * |
Use Proxy |
307 * |
Temporary Redirect |
|
4xx |
Client-Fehler
400 |
Bad Request |
401 |
Unauthorized |
402 * |
Payment Required |
403 |
Forbidden |
404 |
Not Found |
405 * |
Method Not Allowed |
406 * |
Not Acceptable |
407 * |
Proxy Authentication Required |
408 * |
Request Time-out |
409 * |
Conflict |
410 * |
Gone |
411 * |
Length Required |
412 * |
Precondition Failed |
413 * |
Request Entity Too Large |
414 * |
Request-URL Too Large |
415 * |
Unsupported Media Type |
416 * |
Requested range not satisfiable |
417 * |
Expectation Failed |
|
5xx |
Server-Fehler
500 |
Internal Server Error |
501 |
Not Implemented |
502 |
Bad Gateway |
503 |
Service Unavailable |
504 * |
Gateway Time-out |
505 * |
HTTP Version not supported |
|
[Zum Inhaltsverzeichnis]
[Zum Inhaltsverzeichnis]
Letzte Änderung: 05. Mai 2001
Martin Vorländer
EMail beruflich: mv@pdv-systeme.de
EMail privat: martin.vorlaender@t-online.de
WWW: http://vms.pdv-systeme.de/users/martinv/