Prof. Dr. Detlef Stern

Zwei Mini-Webserver für HTTP Basic Auth

Im letzten Beitrag motivierte ich, weshalb es lohnend sein kann, HTTP Basic Authentication als Infrastruktur für Benutzeranmeldungen zu nutzen. Wesentlich Punkt: mit einer einfachen HTTP(s)-Anfrage kann jede Anwendung diesen sicherheitskritischen Faktor delegieren.

Im Beitrag sprach ich einen kleinen Mini-Webserver an, der gut während der Programmierung genutzt werden kann. Der Webserver braucht nur jede HTTP-Anfrage entgegen nehmen und die als authentifiziert zu melden, sobald Benutzername und Passwort gesendet wurden und der Benutzername nicht mit dem Buchstaben x beginnt. Als authentifiziert gilt eine Anfrage, wenn der HTTP-Statuscode 200 vom Webserver zurückgegeben wird. Ein Statuscode 401 signalisiert, dass kein Benutzername / Passwort gesendet wurden, der Code 403 bedeutet, dass der Zugriff nicht erlaubt ist.

Python

Natürlich hatte ich in der Vergangenheit schon einen solchen Mini-Webserver implementiert. Er ist in Python programmiert und verwendet das Web Server Gateway Interface (WSGI) zur Anbindung an Webserver. Der in den Python-Bibliotheken mitgelieferte HTTP Server ist explizit höchstens für Demonstrationszwecke geeignet. Unter Last, manchmal möchte man die auch als Programmierer zu Testzwecken erzeugen, ignoriert der Server gerne mal Anfragen. Um auch unter Last Anfragen ausliefern zu können, verteilt der Gunicorn per WSGI die Anfragen.

Mit diesem Mini-Webserver bin ich nur teilweise zufrieden. Um ihn in Betrieb zu nehmen, kann ich entweder den von Python mitgelieferten HTTP-Server verwenden oder muss Gunicorn in eine zu erstellende virtuelle Umgebung installieren und konfigurieren. Um mir das etwas einfacher, klarer zu machen, habe ich ein Docker-Image mit dem Mini-Webserver und Gunicorn erstellt. So verpackt ist der Mini-Server etwas einfacher nutzbar. Vorausgesetzt, man nutzt Docker.

Der Quelltext für diesen Mini-Webserver py-auth-s steht auf Github zur Verfügung: https://github.com/t73fde/py-auth-s.

Go

Die relative Unzufriedenheit mit dem Mini-Webserver in Python äußerte ich (indirekt) in dem Beitrag über die Sprache Go. Ich wollte den Mini-Webserver in Go neu implementieren.

Dieser steht nun als go-auth-s unter https://github.com/t73fde/go-auth-s zur Verfügung.

Im Vergleich fällt die relative Ähnlichkeit beider Quelltexte auf. Tatsächlich hatte ich versucht, die Python-Version nicht als Vorbild zu nehmen und statt dessen die dokumentierten Go-Konventionen zu verwenden. Entweder denke ich immer auf eine ähnliche Art und Weise oder die Go-Konventionen sind ein wenig an Python orientiert. Oder beides.

Zum anderen fällt auf, dass die Go-Version wesentlich weniger Hilfsdateien benötigt, selbst wenn man die Docker-spezifischen Dinge beiseite lässt. Dies ist eines der Entwicklungsziele von Go gewesen: nur der reine Quelltext soll nötig sein, um die Software zu bauen. Da hat, in meinem Beispiel, funktioniert.

Gut funktioniert hat ebenfalls das Bauen der ausführbaren Programme für Linux, macOS und Windows. Man muss nur einige Umgebungsvariablen angeben und dann werden diese Version z.B. auf meinem Laptop des Jahrgangs 2009 (!) unter Debian 10 erstellt. So können meine Studenten diese gleich für ihre eigenen Rechner nutzen, ohne dass diese Go installieren müssen.

Die ausführbaren Programme scheinen mit ca. 5 MiB etwas groß zu sein. Vergleicht man diese aber mit der Größe des Docker-Image für die Python-Version, dass ähnlich direkt nutzbar ist, so sind 5 MiB etwas weniger als 105 MiB. Gepackt sind die Go-Programme übrigens nur ca. 2 MiB groß. Da ist also noch etwas Potential bei den Entwicklern von Go.

Das Laufzeitverhalten der Go-Version ist soweit ganz gut. Offensichtlich hat der mit Go mitgelieferte HTTP-Server seine Qualitäten und kann auch im Produktivbetrieb eingesetzt werden. Die Go-Version verbraucht auf meinem 10 Jahren alten Laptop etwa 10 MiB Hauptspeicher (und belegt ca 175 MiB virtuellen Speicherm was aber nicht weiter stört). Ein erster Benchmark bestätigt die Qualität, denn es können ca. 6200 Anfragen/s verarbeitet werden.

Die Python-Version verbraucht ca. 17 MiB Hauptspeicher (und belegt dafür nur 7 MiB virtuellen Speicher, was keinen stört), schafft aber nur ca. 1600 Anfragen/s. Diese Zahl ändert sich in der Docker-Version kaum, aber auf Kosten eines wesentlich größeren Hauptspeicherverbrauchs (ca. 115 MiB) und dem beseren Verhalten unter großer Last.

Wen es interessiert, die Anzahl der Anfragen pro Sekunde habe ich mit

ab -t 10 -c 10 -A a:b http://127.0.0.1:9876/

ermittelt, den Speicherverbrauch mit ps -ef.

Mir ist klar, dass diese Zahlen nicht zu ernst genommen werden sollten. Go-Programme sind nicht per se zigmal „schneller“ als Python-Programme. Selbst ein Hauptspeicherverbrauch von 115 MiB ist bei den heutigen Hauptspeichergrößen tief im GiB-Bereich für die meisten nicht relevant (aber vermutlich für Cloud-Betreiber).

Ich fand zwei Ergebnisse sehr erhellend: selbst ein Go-Neuling wie ich (auch wenn ich schon seit 39 Jahren mehr oder minder programmiere) kann mit wenig Aufwand einen einfachen und stabilen Webserver programmieren. Das versprich auch einen Einsatz in der Lehre für meine Studenten.

Zweitens, die Werkzeuge für die Programmiersprache Go machen selbst für mich IDE-Verachter (und Vim- und Zsh-Liebhaber) einen guten Eindruck. An der Qualität, mit wenig Aufwand eine einfach auslieferbare Software zu erstellen, können sich Sprachen wie Erlang, Elixir (die für die Zukunft ein großes Potential besitzen) oder offensichtlich Python gerne eine Scheibe abschneiden. Aber das wäre ein anderer Blog-Beitrag.