Aus Raspberry Pi Geek 08/2022

Mit einfachen Mitteln einen Webserver programmieren (Seite 3)

Auch hier sendet der Browser einen Header, in dem er angibt, dass er einen Post machen will. Sie können ganz einfach selber testen, wie so eine Post-Anfrage aussieht, indem Sie das Kommando aus Listing 6 ausführen. Anschließend rufen Sie im Browser das Webformular im Root-Ordner auf und senden eine Datei (Abbildung 3). Nach ein paar Sekunden unterbrechen Sie das Netcat-Kommando mit [Strg]+[C]. Im Browser erscheint die Meldung Datei angekommen, und die Datei befindet sich dort, wohin Sie umgeleitet wurde. Allerdings handelt es sich noch um keine anzeigbare JPEG-Datei, da das gespeicherte File zum Beispiel noch den Header enthält (Abbildung 4).

Listing 6

POST-Simulation

$ echo "Datei angekommen" | netcat -l 8081 > upload/dateix.jpg
Abbildung 3: Über das Webformular laden Sie Dateien wie Fotos oder Texte auf den Webserver hoch.

Abbildung 3: Über das Webformular laden Sie Dateien wie Fotos oder Texte auf den Webserver hoch.

Abbildung 4: Die Upload-Anfrage enthält noch zahlreiche Daten, die nicht zur hochgeladenen Datei gehören.

Abbildung 4: Die Upload-Anfrage enthält noch zahlreiche Daten, die nicht zur hochgeladenen Datei gehören.

Listing 7 zeigt, wie Sed überschüssige Daten wegschneidet, die nicht zu der hochgeladenen Datei gehören. Diese Aufgabe übernimmt der in der While-Schleife ab Zeile 9 enthaltene Code. Er entfernt den Header, Boundary-Angaben, den Dateinamen und Ähnliches. Um zu vergleichen, wie die Daten ursprünglich ausgesehen haben, werfen Sie einen Blick in die Cache-Datei, die sich ebenfalls im Upload-Ordner befindet. Würde Sed nicht alles Unnötige wegschneiden, könnte das Betriebssystem die empfangenen Dateien nicht korrekt darstellen.

Listing 7

Ausfiltern

function run_post_server () {
message_for_post='HTTP/1.1 200 OK
Content-Length: 17
Connection: close
Datei angekommen'
while true; do
  cat <<< $message_for_post | netcat -l $HTTP_POST_PORT > "${CACHE_DATEI}"
  neuer_name=$( sed -r -n '/filename/{ s/(.*)(filename=")(.+)(".*)/\3/; p}' ${CACHE_DATEI} )
  upload_path="${HTTP_UPLOAD}/${neuer_name}"
  sed '1,/filename/d;/Content-Type/{N;d};$d' ${CACHE_DATEI} > "${upload_path}"
done
}
run_post_server &

Die Routine ruft im Hintergrund zudem die Funktion run_post_server auf (letzte Zeile). Sie enthält eine passende Antwort für POST-Anfragen, die die Länge des Inhalts in Bytes angibt sowie die Informationen enthält, dass nach dem Lesen die Verbindung gekappt werden soll. Ohne diese Angaben würde Firefox die Verbindung einfach halten, obwohl die Daten schon gesendet wurden. Die Funktion startet im Hintergrund (&), damit sie nicht alles blockiert, sobald Dateien gesendet werden.

Ungeprüft

Auch wenn ein Webbrowser explizit nach dem Root-Verzeichnis oder einer anderen Datei fragt, kann der Webserver im Prinzip zurückschicken, was auch immer Sie wollen – Sie müssen es für den Browser nur dementsprechend deklarieren. Ein Beispiel dafür zeigt Listing 8. Der Browser zeigt in diesem Fall beim Aufruf von localhost:8080 oder IP-Adresse:8080 sofort eine JPEG-Datei an, ohne sich darüber zu beschweren.

Listing 8

JPEG-Datei senden

#!/bin/bash
header="HTTP/1.1 200 OK"
datei="http_home/upload/IMG-20220213-WA0002.jpg"
content_length="Content-Length: $( cat $datei | wc --bytes )"
content_type="Content-Type: image/jpeg"
cat $datei | sed -r -e "1 i $header" -e \
    "1 i $content_length" -e \
    "1 i $content_type" -e \
    "1 i Connection: close\n" | netcat -l 8080

Interessant daran ist nicht nur, dass das funktioniert: Es stellt auch eine potenzielle Sicherheitslücke dar. Offenbar überprüfen die meisten Webbrowser überhaupt nicht, ob die Anforderung im GET-Request und die zurückgelieferte Seite zusammenpassen. Im diesem Fall hat der Browser nach der Indexseite des Webservers verlangt und stattdessen eine JPEG-Datei erhalten. Das ist ungefähr so, als würde ein Tennisspieler von seinem Gegenspieler auf einmal mit einem Basketball beworfen.

Erfahrungsgemäß sind solche Eigenheiten und auch andere Features, die man möglicherweise implementieren möchte, im Web nur unzureichend oder auch gar nicht dokumentiert [6]. Deswegen hilft es, mitzuschneiden, was Firefox und andere Browser anfragen. Die Funktion aus Listing 9 ist für den Start des Servers verantwortlich. Sie sehen dort zwei tee-Umleitungen, die alle Daten zum Debuggen in eine Log-Datei weiterleiten. In diesem Protokoll finden Sie dann mit Datum und Uhrzeit versehen, was jeweils der Webbrowser als Anfrage gesendet und der Server als Antwort darauf zurückgeschickt hat (Abbildung 5). So können Sie jede Anfrage und Antwort analysieren und nachvollziehen, was genau während der Kommunikation zwischen Client und Server geschieht.

Listing 9

Webserver aufrufen

function run_server () {
  while true; do
    date | sed -r 's/^|$/\n/g' >> debug
    antworten < $FIFO_GET | tee --append debug |
      netcat -l $HTTP_GET_PORT |
    tee --append debug > $FIFO_GET
  done
}
Abbildung 5: Ein Ausschnitt aus der Debug-Datei f&uuml;r den Port&nbsp;8080. Genauer l&auml;sst sich die Kommunikation zwischen Webserver und Webbrowser nicht mitverfolgen.

Abbildung 5: Ein Ausschnitt aus der Debug-Datei für den Port 8080. Genauer lässt sich die Kommunikation zwischen Webserver und Webbrowser nicht mitverfolgen.

Viele Browser fragen zum Beispiel nach dem berühmten favicon.ico, wenn sie etwas länger mit einem Server kommuniziert haben. Dabei handelt es sich um das Icon, das Sie meist oben in den Tabs der Browser sehen. Es liegt normalerweise im Root-Ordner des Webservers.

Falls Sie möchten, dass auch Ihr Eigenbau-Server ein Favicon zur Verfügung stellt, müssen Sie erst herausfinden, wie eine entsprechende Anfrage des Browsers aussieht, um dann den Server passend reagieren zu lassen. Dass der Webbrowser des Öfteren nach dieser Datei fragt, können Sie an der Fehlermeldung cat: http_home/favicon.ico: Datei oder Verzeichnis nicht gefunden in der Protokolldatei erkennen. Der Browser fordert die Icon-Datei also eigenständig an.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 7 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben