Klassisches CGI
Ein Prozess pro Request. Einfach zu verstehen und zu isolieren, aber teuer bei vielen oder schweren Aufrufen.
Nicht Web als Oberfläche. Sondern Web als Prozess, Ausgabe, Fehler und Spur im Log.
Ein großer Teil früher Webpraxis bestand nicht aus glatten Frontends, sondern aus Dingen, die für Außenstehende kaum sichtbar waren: Shell-Accounts, Dateirechte, CGI-Verzeichnisse, Header-Ausgabe, Formularparameter, Server-Umgebungsvariablen und am Ende vor allem Logfiles. Wer in den 1990er-Jahren mit dem Web ernsthaft arbeitete, lernte sehr schnell, dass eine Seite nicht nur aus HTML bestand. Sie bestand genauso aus Zuständen, Übergaben, Fehlermeldungen und der nüchternen Frage, warum ein Server etwas gerade nicht tat.
CGI war dabei kein modischer Zusatz, sondern der praktische Weg, aus statischer Auslieferung echte Reaktion zu machen. Ein Formular kam herein, ein Skript lief, ein Header musste stimmen, eine Ausgabe musste sauber codiert werden, Rechte mussten passen, und wenn etwas schieflief, stand die Wahrheit oft nicht auf dem Bildschirm, sondern im Error-Log. Gerade dort begann die eigentliche Arbeit.
Diese Seite hält diese Schicht bewusst nüchtern fest: CGI als Übergang zwischen Webserver und Programm, typische Perl-Praxis, GET und POST, Umgebungsvariablen, Headerfehler, Access- und Error-Logs, Debugging sowie die Art von geduldiger Systemarbeit, bei der man nicht rät, sondern liest.
CGI – das Common Gateway Interface – war im frühen Web der schlichte Mechanismus, mit dem ein Webserver ein externes Programm starten und dessen Ausgabe als HTTP-Antwort zurückgeben konnte. Das klingt heute fast banal. Damals war es der entscheidende Schritt vom reinen Dokumentabruf zur tatsächlich reagierenden Website.
Eine statische HTML-Datei musste nur gelesen und ausgeliefert werden. Ein CGI-Skript dagegen wurde bei einem Request tatsächlich ausgeführt. Das hieß: Parameter entgegennehmen, eventuell Daten prüfen, Inhalte zusammensetzen, vielleicht eine Mail verschicken, vielleicht eine Datei lesen oder schreiben und am Ende eine korrekte HTTP-Antwort zurückgeben. Schon damit war das Web nicht mehr nur ein Dokumentenraum, sondern eine Prozessschicht.
Gerade deshalb war CGI so prägend. Es war klein genug, um begreifbar zu sein, und direkt genug, um jeden Fehler sofort offenzulegen. Wer CGI schrieb, spürte unmittelbar, dass der Server nichts „errät“. Fehlt ein Header, ist der Header kaputt. Stimmt die Ausgabe-Reihenfolge nicht, ist die Antwort kaputt. Ist das Skript nicht ausführbar, läuft es nicht. Und wenn der Interpreter ein Problem hat, landet man im Error-Log.
„CGI war keine Magie. Es war nur der Moment, in dem der Server statt einer Datei ein Programm laufen ließ.“
Der Browser spricht nicht direkt mit dem Perl-Skript. Der Webserver bleibt für Verbindung, Request-Lesen, URL-Zuordnung, Zugriffskontrolle und die endgültige HTTP-Antwort zuständig.
Klassisches CGI startet für jeden Request ein neues Programm. Das schafft eine klare Zustandsgrenze: Der Prozess erhält genau seine Umgebung, verarbeitet genau diesen Request und endet wieder.
Ein Prozess pro Request. Einfach zu verstehen und zu isolieren, aber teuer bei vielen oder schweren Aufrufen.
Apache-Module für CGI-Ausführung; mod_cgid verlagert das Starten externer Programme auf geeigneten Unix-MPMs in einen Daemon.
Dauerhafte Anwendungsprozesse vermeiden wiederholten Interpreterstart, müssen aber Speicher, globalen Zustand und Request-Trennung sauber behandeln.
Kein Anwendungsprozess pro Abruf. Wo keine Eingabe- oder Zustandslogik benötigt wird, bleibt das die kleinste Angriffs- und Fehlerfläche.
„Dauerhaft“ ist nicht automatisch sicherer oder einfacher. Klassisches CGI bezahlt mit Prozesskosten; persistente Systeme bezahlen mit langlebigem Zustand, Speicherverwaltung und komplexerer Isolation.
Wer frühe CGI-Praxis nur aus heutiger Framework-Sicht betrachtet, unterschätzt leicht, wie nah das Ganze an der Server- und Benutzerumgebung hing. Man arbeitete nicht in einer abstrahierten Plattform, sondern in einem realen Dateibaum mit Benutzerrechten, Gruppenrechten, Skriptpfaden, Shebang-Zeilen und konkreten Interpreter-Versionen.
Der Shell-Account war dabei oft nicht bloß Bequemlichkeit, sondern Voraussetzung. Man musste Dateien hochladen, Rechte setzen, Skripte direkt aufrufen, vielleicht lokal mit der Shell testen, Logfiles lesen, Verzeichnisse durchsuchen und herausfinden, ob ein Problem im Skript, im Pfad, in den Rechten oder in der Serverkonfiguration lag. Das war keine getrennte DevOps-Welt. Das gehörte schlicht zur Webarbeit dazu.
Diese Nähe zur Infrastruktur war lehrreich. Man sah sehr schnell, dass ein Webprozess keine abstrakte Oberfläche ist, sondern ein ausgelöster Systemvorgang unter konkreten Bedingungen. Wer das einmal sauber begriffen hatte, verlor meistens die Lust an mystifizierten Erklärungen darüber, warum „der Server heute irgendwie spinnt“.
| Variable | Bedeutung und Vorsicht |
|---|---|
| GATEWAY_INTERFACE | CGI-Schnittstellenversion, typischerweise CGI/1.1. |
| REQUEST_METHOD | HTTP-Methode; nicht ungeprüft auf GET und POST beschränken, wenn der Server weitere Methoden durchreicht. |
| QUERY_STRING | Unverarbeiteter Query-Teil ohne führendes Fragezeichen; vollständig untrusted. |
| CONTENT_TYPE | Medientyp des Request-Bodys einschließlich möglicher Parameter wie Charset oder Multipart-Boundary. |
| CONTENT_LENGTH | Dezimale Anzahl der Bytes, die das Skript vom Standardinput lesen darf. |
| SCRIPT_NAME | URL-Pfadanteil, der das Skript identifiziert. |
| PATH_INFO | Zusätzlicher URL-Pfad hinter dem Skript; muss getrennt von Dateisystempfaden behandelt werden. |
| SERVER_NAME / SERVER_PORT | Serveridentität und Port nach Serverkonfiguration; bei Proxybetrieb nicht automatisch öffentliche Ursprungs-URL. |
| REMOTE_ADDR | Netzwerkadresse des direkten Gegenübers; hinter Reverse Proxy häufig Proxyadresse. |
| REMOTE_USER | Vom Server authentisierter Benutzer, sofern eine entsprechende Zugriffsauthentisierung aktiv war. |
| HTTP_* | Aus Client-Headern abgeleitete Werte wie HTTP_USER_AGENT oder HTTP_REFERER; niemals als vertrauenswürdig behandeln. |
Bei einer URL wie /cgi-bin/item.pl/gruppe/42 bezeichnet
SCRIPT_NAME typischerweise das Skript, während
PATH_INFO den zusätzlichen Pfadteil enthält.
Diese Trennung erlaubte früh sprechendere CGI-URLs.
PATH_INFO ist jedoch kein geprüfter lokaler Dateiname.
Punkte, Schrägstriche, Kodierung und Normalisierung können zwischen
URL-, Server- und Betriebssystemebene unterschiedlich behandelt werden.
open, unlink oder Shellkommandos weiterreichen.
Einer der frühesten und wichtigsten Lerneffekte bei CGI war die Tatsache, dass die Antwort formal beginnen musste. Bei einer normalen Dokumentantwort liefert das Skript mindestens Content-Type; fehlt ein eigener Status-Header, wird üblicherweise Status 200 angenommen. Nach den Headerfeldern folgt eine leere Zeile und erst danach der optionale Message-Body.
Für heutige Systeme klingt das trivial. In der frühen Praxis war es eine konstante Fehlerquelle. Ein zusätzliches Leerzeichen an falscher Stelle, eine Warnung vor dem Header, eine kaputte Zeichenausgabe, ein Modulhinweis, ein Debug-Print zu früh – und schon war die Antwort aus Sicht des Servers beschädigt. Der Browser zeigte oft nur einen generischen Fehler. Das Error-Log hingegen war meist präziser.
Gerade daran lernte man ein frühes Gefühl für Protokolldisziplin. Das Problem war selten „CGI allgemein“. Das Problem war meistens sehr konkret: falscher Header, Header zu spät, Zeichensatzfrage, ungewollte Ausgabe, fehlende Leerzeile oder ein Skriptabbruch, bevor überhaupt ein Header zurückgegeben wurde.
| Antwort | Typische Felder |
|---|---|
| Dokument | Content-Type, optional Status und weitere erlaubte Response-Header, danach Body. |
| Fehlerstatus | Status: 400 Bad Request oder anderer Status plus Content-Type und erklärender Body. |
| Client-Redirect | Location mit absoluter URI; Server erzeugt daraus die Weiterleitungsantwort. |
| Lokaler Redirect | Location mit lokalem Pfad; Server verarbeitet das neue Ziel intern nach seiner Konfiguration. |
Ein CGI-Skript sollte erwartbare Benutzerfehler nicht als unkontrollierten Prozessabbruch behandeln. Eine definierte 4xx-Antwort ist diagnostisch und betrieblich klarer als ein generischer 500er.
Die begriffliche Trennung zwischen GET und POST war früh klar, aber in der Praxis musste man sie wirklich verstehen, nicht nur benennen. GET übergibt Parameter im Query-Teil der URL – sichtbar, speicherbar und leicht bookmarkbar. POST trägt Daten gewöhnlich im Request-Body. Das verändert Semantik und Transportform, schafft aber ohne TLS keinerlei Vertraulichkeit.
| Methode | Praktische Eigenschaft |
|---|---|
| GET | Für sichere, abrufende Operationen und teilbare URLs geeignet. Query-Daten können in Verlauf, Lesezeichen, Referer und Logs erscheinen. |
| POST | Für Verarbeitung oder Zustandsänderung geeignet. Body-Daten stehen nicht im normalen URL-Feld, können aber von Anwendung, Proxy oder Diagnosewerkzeugen protokolliert werden. |
Das Entscheidende lag jedoch nicht nur in der Methode selbst, sondern in der Verarbeitung. URL-Decoding, Pluszeichen als Leerzeichen, Prozentkodierung, Sonderzeichen, Zeilenumbrüche, Zeichensatzprobleme – all das musste das Skript sauber behandeln. Wer dabei nachlässig war, bekam keine abstrakte Theoriediskussion, sondern kaputte Formulardaten, abgeschnittene Felder oder später sogar Sicherheitsprobleme.
| Medientyp | Verarbeitung |
|---|---|
| application/x-www-form-urlencoded | Schlüssel-Wert-Paare mit Prozentkodierung; Plus wird in Formularsemantik häufig als Leerzeichen interpretiert. |
| multipart/form-data | Mehrteiliger Body mit Boundary; notwendig für reguläre Dateiuploads und komplexere Formularteile. |
| text/plain | Für HTML-Formulare technisch möglich, aber mehrdeutig und für zuverlässige strukturierte Verarbeitung ungeeignet. |
| application/json | Keine klassische HTML-Formularcodierung, aber bei moderneren CGI-Endpunkten möglich; eigenen Parser und klare Größen-/Typgrenzen verwenden. |
Das Skript darf nicht unabhängig vom CONTENT_TYPE denselben
Parser verwenden. Besonders Multipart-Daten sollten mit einer bewährten
Bibliothek verarbeitet werden; selbstgeschriebene Boundary-Parser sind
fehleranfällig.
Ein Parametername kann mehrfach vorkommen:
tag=unix&tag=perl. Ein Parser muss deshalb festlegen,
ob er eine Liste, den ersten oder den letzten Wert liefert.
Stillschweigende Unterschiede zwischen Bibliotheken können
Sicherheitsprüfungen und Anwendungslogik auseinanderlaufen lassen.
Frühes CGI war oft praktisch gleichbedeutend mit Perl. Nicht weil Perl die einzige Möglichkeit gewesen wäre, sondern weil es auf vielen Systemen vorhanden, textstark, pragmatisch und gut genug für genau diese Übergangsschicht war. Formulare lesen, Strings zerlegen, Mail zusammensetzen, Dateien öffnen, Datum und Zeit formatieren, kleinere Zustände verwalten – all das ließ sich in Perl mit vergleichsweise wenig Aufwand umsetzen.
Gleichzeitig war Perl kein Schutzraum. Wenn das Skript schlampig war, war das Ergebnis schlampig. Wenn Variablen unklar geführt wurden, wurde die Fehleranalyse unangenehm. Wenn reguläre Ausdrücke schlecht saßen oder Eingaben blind übernommen wurden, entstanden echte Probleme. Gerade deshalb war frühe Perl-Praxis für viele lehrreich: nicht wegen Eleganz im akademischen Sinn, sondern weil sich die Folgen jeder Nachlässigkeit unmittelbar zeigten.
Stringverarbeitung, kleine Webformulare, Mail-Dispatch, Zustandsdateien, schnelle Prototypen, klare Textausgabe.
unsaubere Eingabeprüfung, Dateirechte, Shell-Aufrufe, Zeichensatzfragen, nicht abgefangene Warnungen, schwer lesbar gewordene Ein-Datei-Skripte.
Wer mit Perl-CGI arbeitete, lernte außerdem etwas Wichtiges über Webdynamik: Der eigentliche Aufwand lag selten im sichtbaren HTML. Der Aufwand lag in korrekter Übergabe, validen Zuständen und reproduzierbarer Fehlersuche. Genau deshalb waren Access- und Error-Logs kein Nebenthema, sondern permanenter Bestandteil der Arbeit.
-T zusätzliche Prüfungen für fremd beeinflusste Daten aktivieren, ist aber kein Ersatz für Validierung oder ein Berechtigungsmodell.Für viele war CGI zuerst über Formulare sichtbar. Kontaktformulare, einfache Bestellanfragen, Gästebuch-Einträge, kleine Suchmasken oder Konfigurationsübergaben – all das lief im Kern auf dieselbe Frage hinaus: Wie kommen Benutzereingaben kontrolliert auf dem Server an und was passiert dann damit? Browserseitige Pflichtfelder und JavaScript waren dabei nur Bedienhilfe; die maßgebliche Prüfung musste serverseitig erfolgen.
In der frühen Praxis war das häufig ein Mail-Skript. Der Browser schickte ein Formular, CGI nahm Felder entgegen, prüfte sie mehr oder weniger gut und setzte daraus eine E-Mail oder eine lokale Datendatei zusammen. Technisch simpel, praktisch aber voller Fallstricke: fehlende Feldprüfung, ungefilterte Sonderzeichen, kaputte Newlines, Header-Manipulation, falsche Rechte auf temporären Dateien oder ein Sendmail-Aufruf, der lokal anders funktionierte als gedacht.
Gerade daran trennte sich frühe Webromantik von tatsächlicher Webarbeit. Ein Formular war eben nicht „fertig“, nur weil es hübsch erschien. Es war erst dann brauchbar, wenn Eingaben sauber entgegengenommen, protokolliert, geprüft und nachvollziehbar verarbeitet wurden.
Gästebücher, Zähler und einfache Formularablagen schrieben häufig direkt in Dateien. Genau dort entstanden Nebenläufigkeits- und Rechteprobleme: zwei gleichzeitige Prozesse konnten denselben Stand lesen und einander anschließend überschreiben.
Ein erfolgreiches open bedeutete noch nicht, dass ein
Mehrbenutzerbetrieb korrekt war. CGI machte Nebenläufigkeit selbst bei
kleinen Seiten zu einer realen Systemfrage.
Bei klassischem CGI werden Interpreter, Module und Programmlogik für jeden Request neu gestartet. Für gelegentliche Formulare war das oft akzeptabel; bei hohem Verkehr oder großen Abhängigkeiten wurde es teuer.
| Ursache | Auswirkung und Behandlung |
|---|---|
| Interpreterstart | CPU- und Speicheraufwand je Request; kleine Skripte und wenige Module helfen. |
| Externe Programme | Weitere Prozesse, Wartezeiten und zusätzliche Fehlerpfade. |
| Langsame Clients | Request-Lesezeiten müssen auf Serverebene begrenzt werden. |
| Große Bodies | Vor dem Einlesen server- und anwendungsseitig begrenzen. |
| Dauerhafte Alternativen | FastCGI/PSGI sparen Startkosten, verlangen aber saubere Request-Trennung und Lebenszyklusverwaltung. |
Das Access-Log war die rohe Spur des Verkehrs. Dort stand nicht die philosophische Bedeutung eines Zugriffs, sondern ganz praktisch: wann etwas angefordert wurde, von welcher direkten Netzwerkadresse, mit welcher Methode, auf welches Ziel, mit welchem finalen Statuscode, in welcher Größe und – je nach Format – mit welchem Referer oder User-Agent. Hinter Proxy oder Loadbalancer ist die protokollierte Gegenstelle nicht automatisch der ursprüngliche Benutzer.
Für frühe Webarbeit war das enorm nützlich. Man sah, ob eine Seite wirklich aufgerufen wurde, ob ein CGI-Endpunkt 200 oder 500 lieferte, ob ein Formular mit GET statt POST ankam, ob ein Bot über alte Pfade lief oder ob jemand immer wieder dieselbe defekte URL abfragte. Das Access-Log war damit kein Statistikspielzeug, sondern Betriebsprotokoll.
Gerade in Kombination mit dem Error-Log wurde daraus eine brauchbare Arbeitsmethode: Im Access-Log sah man, dass etwas passiert war. Im Error-Log sah man oft, warum es scheiterte.
Apache kann das Zugriffsformat über LogFormat festlegen.
Das klassische Common Log Format enthält Gegenstelle, Identität,
Benutzer, Zeitpunkt, Requestzeile, finalen Status und übertragene Bytes.
Das Combined Log Format ergänzt Referer und User-Agent:
%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"| Token | Bedeutung |
|---|---|
| %h | Remote Host beziehungsweise Adresse nach Serverauflösung. |
| %l | Identd-Wert; in der Praxis meist Bindestrich. |
| %u | Authentisierter Remote-Benutzer oder Bindestrich. |
| %t | Zeitpunkt des Requests im konfigurierten Logformat. |
| %r | Erste Requestzeile mit Methode, Ziel und Protokollversion. |
| %>s | Finaler Status nach internen Weiterleitungen. |
| %b | Antwortgröße ohne Header; Bindestrich bei null Bytes. |
Logfelder sind Beobachtungen, keine automatisch verifizierten Tatsachen. Referer und User-Agent stammen gewöhnlich direkt aus Client-Headern.
| Klasse | Diagnostische Einordnung |
|---|---|
| 2xx | Request wurde verarbeitet; fachlicher Inhalt kann trotzdem falsch oder unvollständig sein. |
| 3xx | Weiterleitung oder Bedingungsantwort; Ziel und Redirect-Schleifen prüfen. |
| 4xx | Request, Berechtigung oder Ressource passt nicht; 404 kann echter Altlink oder automatischer Scan sein. |
| 5xx | Server- oder Anwendungsfehler; Error-Log und CGI-STDERR unmittelbar daneben auswerten. |
Ein 200er beweist nur, dass der Server eine erfolgreiche Antwort geliefert hat. Er beweist nicht, dass eine Mail zugestellt, ein Datensatz dauerhaft geschrieben oder eine fachliche Transaktion korrekt abgeschlossen wurde.
Das Error-Log war für CGI meistens der eigentliche Arbeitsplatz. Browserfehler waren oft unpräzise. Eine leere Seite, ein 500 Internal Server Error oder einfach nur eine kaputte Antwort sagten wenig. Das Error-Log dagegen sagte häufig das Entscheidende: Syntaxfehler, fehlende Module, falscher Interpreterpfad, unzulässige Rechte, Header-Probleme, Warnungen vor dem Header, Datei nicht gefunden, uninitialisierte Variablen oder Shell-Aufrufe, die nicht durchliefen.
Wer ernsthaft mit CGI arbeitete, gewöhnte sich früh an diese Reihenfolge: Nicht zuerst den Browser anstarren, sondern das Error-Log lesen. Dort lag meistens die eigentliche Wahrheit. Und wenn dort nichts stand, war das auch eine Information – dann musste man die Logkonfiguration, die Rechte oder den tatsächlichen Ausführungspfad prüfen.
Ein CGI-Programm sollte Diagnosemeldungen auf Standardfehler und die eigentliche CGI-Antwort auf Standardoutput schreiben. Vermischen sich beide Kanäle, können Warnungen vor dem Header eine ansonsten richtige Antwort zerstören.
Access- und Anwendungslogs können IP-Adressen, Zeitpunkte, aufgerufene Pfade, Query-Strings, Referer, User-Agent, Benutzernamen und fachliche Vorgänge zusammenführen. Schon eine URL kann Suchbegriffe, interne IDs oder persönliche Angaben enthalten.
Die konkrete rechtliche Bewertung gehört in die aktuelle Datenschutz- und Betriebsdokumentation der Domain, nicht in eine historische CGI-Anleitung.
Requestziele und Header können vom Client beeinflusst sein. Rohlogs können deshalb Steuerzeichen, täuschende Zeilenumbrüche, Terminalsequenzen oder absichtlich irreführende Texte enthalten.
Ein laufender Webserver hält Logdateien geöffnet. Nur eine Datei umzubenennen oder zu löschen garantiert deshalb nicht, dass der Prozess sofort in eine neue Datei schreibt.
Apache kann Logs auch an ein Rotationsprogramm weiterleiten. Dieses Modell vermeidet manuelle Signalfolgen, erhöht aber die Abhängigkeit von einem weiteren laufenden Prozess.
Frühe CGI-Arbeit bedeutete oft Debugging ohne die Bequemlichkeiten späterer Entwicklungsumgebungen. Kein hübscher Live-Inspector, kein eingebauter Stacktrace im Browser, kein vollintegriertes Observability-System. Stattdessen: Skript lokal aus der Shell aufrufen, Testparameter manuell setzen, Header-Ausgaben kontrollieren, temporäre Debug-Ausgaben einbauen, Logfiles lesen und dann die Kette aus Request, Skript und Antwort gedanklich sauber nachverfolgen.
Gerade diese Reduktion hatte einen Vorteil: Man lernte, die Schichten zu trennen. Läuft das Skript überhaupt? Kommt der Interpreter hoch? Sind die Variablen gesetzt? Ist die Methode korrekt? Ist die Content-Length als Bytezahl plausibel und innerhalb des Limits? Kommt vor dem Header ungewollte Ausgabe? Ist ein Dateipfad relativ falsch? Ist ein Modul vorhanden? Jede Frage griff in eine andere Ebene – und genau so musste man sie behandeln.
Reproduzieren, Access-Log prüfen, Error-Log lesen, Skript direkt testen, Eingabedaten isolieren, Ausgabeformat kontrollieren, Rechte und Pfade verifizieren.
Weniger Vermutung, mehr Eingrenzung. Weniger Oberfläche, mehr tatsächlicher Laufweg. Genau dort wurde frühe Webarbeit ernst.
„Debugging hieß oft nicht, auf eine IDE zu warten. Es hieß lesen, was wirklich passiert war.“
Ein Skript kann in einer kontrollierten Shellumgebung mit denselben Kernvariablen und Eingabebytes getestet werden. Dadurch trennt man Parser- und Programmlogik vom Webserver.
Der Test muss mit derselben Interpreterversion, demselben Benutzerkontext, denselben Dateirechten und möglichst derselben Umgebung erfolgen. Ein Skript, das als eigener Shell-Benutzer funktioniert, kann unter dem Webserverkonto weiterhin an Rechten oder Pfaden scheitern.
Frühes CGI war nicht nur praktisch, sondern auch berüchtigt für naive Lösungen. Gerade Mail-Skripte, Gästebücher, Suchmasken, Dateioperationen oder Shell-nahe Hilfsskripte wurden oft schnell geschrieben und schlecht abgesichert. Das war nicht bloß ein historischer Schönheitsfehler. Ein CGI-Programm kann grundsätzlich mit allen Rechten des ausführenden Serverkontos auf Systemressourcen zugreifen, die dieses Konto erreichen darf.
Typische Probleme waren ungeprüfte Eingaben, blindes Durchreichen an Shell-Aufrufe, Header-Injection in Mail-Skripten, Dateipfade mit unzureichender Kontrolle, schreibbare Verzeichnisse ohne klare Trennung oder schlicht ein zu großes Vertrauen in das, was „der Benutzer schon nicht absichtlich falsch machen wird“.
Genau deshalb blieb von dieser Zeit nicht nur Webromantik, sondern auch ein dauerhafter Reflex: lieber weniger Dynamik, wenn sie nicht wirklich gebraucht wird; lieber klare serverseitige Prüfung; lieber statische Auslieferung dort, wo keine Prozesslogik nötig ist. Wer frühe CGI-Fehler gesehen hatte, brauchte keine Theorie darüber, warum unnötige Dynamik unnötige Risiken mitbringt.
| Klasse | Technische Ursache und Abwehr |
|---|---|
| Command Injection | Benutzerdaten werden Teil eines Shellkommandos; Shell vermeiden, Argumente trennen, Allowlist und geringste Rechte verwenden. |
| Header Injection | CR/LF aus Formularwerten erzeugen zusätzliche Mail- oder HTTP-Header; Zeilenumbrüche ablehnen und Headerbibliotheken verwenden. |
| Path Traversal | Benutzerpfad verlässt das erlaubte Verzeichnis; IDs statt Pfade, kanonisieren und Basisgrenze prüfen. |
| Cross-Site Scripting | Fremde Daten werden ohne kontextgerechte HTML-Ausgabecodierung zurückgegeben. |
| CSRF | Authentisierte oder zustandsändernde Operation wird durch fremde Seite ausgelöst; Token und geeignete Same-Site-/Origin-Prüfung verwenden. |
| Upload-Missbrauch | Dateityp, Größe, Inhalt, Name oder Speicherort werden nicht begrenzt; außerhalb des Webroots speichern und verifizieren. |
| Resource Exhaustion | Große Bodies, langsame Requests, teure Regexe oder endlose externe Prozesse; Limits und Timeouts setzen. |
| Secret Leakage | Passwörter, Tokens, Umgebungen oder Formulardaten gelangen in HTML oder Logs; Redaction und Minimalprotokollierung. |
Ein CGI-Skript muss nicht kompromittiert sein, um einen Server zu überlasten. Eine formal gültige Eingabe kann zu groß, zu langsam oder zu rechenintensiv sein.
Limits gehören auf mehrere Ebenen: Webserver, Betriebssystem, CGI-Programm und gegebenenfalls nachgelagerter Dienst.
Rückblickend liegt ein wesentlicher Wert dieser Zeit nicht einmal nur in CGI selbst, sondern im Umgang mit Logfiles. Access- und Error-Logs zwangen zu einer Nüchternheit, die später oft verloren ging. Dort stand kein Marketing, kein freundliches Narrativ, keine weichgespülte Zusammenfassung. Dort stand, was passiert war.
Man sah Requests, Fehlercodes, Pfade, Zeitpunkte, Methoden, Warnungen, Headerprobleme und die Folgen kleinster Ausgabefehler. Genau dadurch lernte man, Systeme nicht als Story zu lesen, sondern als Ereignisketten. Diese Art zu denken bleibt nützlich – nicht nur im Web, sondern überall dort, wo Technik nachvollziehbar und wartbar bleiben soll.
Wer so gelernt hat, entwickelt fast automatisch eine Skepsis gegen unnötige Schichten, die das tatsächliche Verhalten verdecken. Nicht weil moderne Werkzeuge grundsätzlich schlecht wären, sondern weil gute Technik lesbar bleiben sollte. Ein Access-Log oder Error-Log ist brutal ehrlich. Gerade das ist sein Wert.
„Logfiles loben nichts. Genau deshalb sind sie brauchbar.“
Ein altes Skript allein reicht nicht. Die Ausführung hing von Webserver, Interpreter, Modulen, Dateirechten, Verzeichnisstruktur, Mailtransport und Konfiguration ab.
CGI/1.1 wird durch RFC 3875 als dokumentierte „current practice“ beschrieben. Die Webserver- und Logabschnitte orientieren sich zusätzlich an der offiziellen Apache-HTTP-Server-Dokumentation; Perl- und Sicherheitsabschnitte an Perl- und OWASP-Unterlagen.
RFC 3875: The Common Gateway Interface Version 1.1
Apache HTTP Server: Dynamic Content with CGI
Apache HTTP Server: mod_log_config und LogFormat
Apache HTTP Server: Security Tips
RFC 3875 ist eine informative Dokumentation der CGI/1.1-Praxis, kein Internetstandard. Webserver und Betriebssysteme können einzelne system- oder implementierungsabhängige Details unterschiedlich behandeln.
CGI war nicht perfekt, nicht elegant in jedem Detail und sicher nicht frei von naiven Konstruktionen. Aber es hatte eine Stärke, die man ernst nehmen sollte: Es machte den Weg zwischen Request, Ausführung und Antwort sichtbar. Gerade deshalb war es eine gute Schule.
Wer mit CGI, Shell-Accounts und Logfiles gearbeitet hat, lernte früh, dass Webentwicklung mehr ist als sichtbares Layout. Sie ist Protokoll, Prozess, Eingabe, Ausgabe, Rechte, Pfadlogik, Nebenläufigkeit, Datenschutz und Fehleranalyse. Genau daraus kommt ein Teil der späteren Vorliebe für ruhige, statische, nachvollziehbare Lösungen.
Die Host- und Account-Seite darunter beschreibt shell-accounts-und-hosts.htm. Die spätere Haltung gegenüber Struktur und Werkzeugen steht auf philosophy.htm. Und die Linie der frühen Webpraxis insgesamt bleibt auf webmaster.htm sichtbar.
Diese Datei gehört zu den Server-, Shell-, Webentwicklungs- und Sicherheitsseiten im sslxy-Bereich.
Diese Seite liegt im sslxy-Bereich der Domain und behandelt historische Webtechnik, CGI-Praxis, Logfile-Arbeit, sichere Eingabeverarbeitung und technische Erinnerungen an frühe Webentwicklung. sslxy ist ein technisches Pseudonym und kein davon getrennt betriebener Anbieter.
Genannte Techniken, Programmiersprachen, Serverbegriffe, Standards, Marken- und Produktnamen dienen ausschließlich der sachlichen technischen und historischen Einordnung. Diese Seite ist keine Empfehlung, veraltete CGI-Skripte oder nicht mehr gepflegte Serverumgebungen ungeprüft öffentlich zu betreiben.
Anbieter und Verantwortlicher der gesamten Domain – einschließlich dieses Unterverzeichnisses – ist der Betreiber des Goldenen Ochsen in Göppingen-Hohenstaufen. Die maßgeblichen Anbieterangaben stehen im zentralen Impressum der Domain; die Informationen zur Datenverarbeitung in der Datenschutzerklärung der Domain.
Logfiles können IP-Adressen, URLs, Zeitpunkte, Benutzerkennungen und andere sensible Informationen enthalten. Beispiele auf dieser Seite verwenden reservierte Dokumentationsadressen und dürfen nicht mit realen Personen oder Zugriffen gleichgesetzt werden.
Kontakt für technische Rückfragen: mail@sslxy.de
Auch diese Unterseite ist als rein informative, statische HTML-Seite konzipiert. Es werden keine Tracker, keine Analyse-Tools und keine zustimmungspflichtigen Cookies eingesetzt.
Statische Seite. Schlanke Struktur. Technischer Inhalt ohne unnötigen Überbau.