OpenVPN handelt aufgrund genau einer Ausgabe eines Anmeldeskripts: des Exit-Status. Alles andere, was das Skript tut, ist Dekoration. Ein Hook kann den richtigen Verifier erreichen, die Antwort auswerten und eine freundliche Zeile ausgeben und dabei einen Status zurückgeben, der das Gegenteil dessen bedeutet, was sein Autor beabsichtigt hat. Lesen Sie zuerst den Vertrag und schreiben Sie den Adapter darum herum, dann verschwindet diese ganze Fehlerklasse.

Der Vertrag ist klein: Identifizieren Sie das übermittelte Konto, stellen Sie dem freigegebenen Verifier die beabsichtigte Frage und akzeptieren Sie nur das dokumentierte positive Ergebnis genau dieses Verifiers für genau diese Anfrage. Alles andere ist Infrastruktur.

Die drei Status, die der Hook zurückgeben kann

Für auth-user-pass-verify definiert OpenVPN-2.6-Handbuch den Exit-Code 0 als Annahme, 1 als Ablehnung und 2 als verzögerte Authentifizierung. Das sind die einzigen drei Antworten, die der Server versteht, und jede hat eine andere Folge für die Verbindung. Ein Skript, das mit dem Status seines letzten Befehls endet, hat faktisch einen Log-Aufruf oder einen Aufräumschritt die Stimme abgeben lassen. Schreiben Sie den Status in jedem Zweig explizit, auch in den Zweigen, die den Verifier nie erreicht haben.

HTTP-Erfolg und Authentifizierungserfolg sind getrennte Ebenen, und ihre Vermischung ist der häufigste Grund, warum dieser Hook schiefgeht. Eine 202-Antwort bedeutet, dass die Anfrage zur Verarbeitung angenommen wurde, nicht dass ein Passwort verifiziert wurde. Definieren Sie den erwarteten Status, die Form der Antwort und das endgültige Urteil aus dem API-Vertrag, den Sie erhalten haben, und erfinden Sie keinen Feldnamen, nur weil er plausibel klingt.

Wenn die Antwort wirklich erst später eintrifft, ist das der verzögerte Pfad, und er muss als solcher gebaut werden. Ein verzögerter Versuch, der nie abgeschlossen wird, hält Ressourcen, bis das Zeitlimit abläuft.

Lesen Sie die Anmeldedatei genau so, wie sie geschrieben ist

Bei der dokumentierten Via-Datei-Methode schreibt der Server Benutzername und Passwort als erste zwei Zeilen einer temporären Datei, übergibt diesen Pfad an das Skript und entfernt die Datei, wenn das Skript zurückkehrt. Lesen Sie diese zwei Zeilen als Daten: Führen Sie die Datei niemals per source aus, werten Sie sie niemals aus und fügen Sie ihren Inhalt niemals in eine Kommandozeile ein, wo die Prozesstabelle ihn sehen kann. Bewahren Sie das Passwort Byte für Byte, denn eine Normalisierung, wie Sie sie bei einem Benutzernamen anwenden würden, verändert die Anmeldedaten still. Das Verzeichnis für diese temporäre Datei ist eine Bereitstellungsentscheidung, bestätigen Sie also, dass es existiert und nicht für alle auf dem Host lesbar ist.

Halten Sie die eigenen Anmeldedaten des Verifiers von denen des Benutzers getrennt: Sie gehören zur Gateway-Integration, leben im Secret Store der Plattform und brauchen nur die Berechtigung zum Verifizieren, sind also kein Beleg dafür, dass eine bestimmte Person sich authentifiziert hat. Lassen Sie den Hook auch nicht zu einem zweiten Passwort-Prüfer werden. Ein Hash-Vergleich von Hand nachzubauen wird nicht dadurch sicher, dass man die Schleife optimiert, und ein gepflegter Verifier kennt bereits das gesalzene, teure Schema des Kontospeichers.

Entscheiden Sie, was eine nicht klassifizierbare Antwort bedeutet

Zeitüberschreitungen, Transportfehler, fehlerhafte Antworten und ein nicht verfügbares Backend teilen eine Eigenschaft: Keines davon ist eine positive Verifikation. Der Hook sollte bei jedem davon geschlossen fehlschlagen und einen Grund protokollieren, auf den ein Betreiber reagieren kann. Dieser Grund gehört in ein geschütztes Protokoll, nicht in eine Nachricht, die der Person zurückgegeben wird, die sich verbinden will.

Seien Sie ebenso sorgfältig bei den Pfaden, die den Verifier überhaupt nicht erreichen. Ein fehlender Konfigurationswert, ein unlesbares Secret oder eine nicht installierte Abhängigkeit sollten eine Ablehnung mit einer eigenen Betriebsmarkierung ergeben statt einer versehentlichen Annahme. Testen Sie diese Zweige, indem Sie die Abhängigkeit in einem Labor entfernen, statt über sie zu spekulieren. Wo ein Fehlschlagen der Protokollierung den Exit-Status ändern kann, ist die Protokollierung Teil der Entscheidung geworden und muss harmlos gemacht werden.

Die Serverkonfiguration spielt auch hier eine Rolle: benutzerdefinierte Skripte werden nur berücksichtigt, wenn die laufende Konfiguration sie auf der erforderlichen Sicherheitsstufe zulässt, und diese Einstellung ist eine bewusste Wahl und kein Standardwert, den man anhebt.

Prüfen Sie das Urteil, nicht die gedruckte Zeile

Bauen Sie einen Test, der den Exit-Status direkt prüft. Schreiben Sie eine Muster-Anmeldedatei, führen Sie den Hook dagegen mit einem bekanntermaßen guten und einem bekanntermaßen schlechten Konto aus und lesen Sie den Status, den die Shell meldet, statt den Text, den das Skript ausgibt. Diese eine Prüfung fängt die meisten Vertragsfehler ab, bevor sich überhaupt ein Client verbindet.

Führen Sie dann dieselben Fälle über einen echten Client gegen einen Nicht-Produktions-Listener aus und bestätigen Sie, was der Server festgehalten hat: angenommen, abgelehnt oder verzögert. Decken Sie ein deaktiviertes Konto, ein falsches Passwort, eine fehlerhafte Verifier-Antwort, eine Zeitüberschreitung und einen nicht erreichbaren Verifier ab. Landet ein Fall in einem Zustand, den Sie nicht benennen können, ist der Adapter nicht fertig.

Halten Sie die Zuordnung vom Verifier-Ergebnis zum Exit-Status neben dem Skript im Repository, damit der nächste Entwickler den Vertrag lesen kann, ohne den Code zurückzuentwickeln.

Ähnliche Artikel