SaaS-Adminbereich hinter dem VPN: welcher Adresse lässt sich trauen?
Der Ursprung sieht die Egress-Adresse deines VPN-Gateways, nicht die Tunneladresse des Laptops. Vertraue nur einem konfigurierten Proxy-Header und sichere dann jede Admin-Operation ab.
Öffentliche SaaS-Seiten können für alle offen bleiben, während die Admin-Operationen dahinter jeden außerhalb des VPN abweisen. Der Mechanismus, der das möglich macht, ist kein verstecktes Menü und keine separate Anmeldeseite; es ist eine Prüfung des Netzwerkpfads, der die Anfrage zugestellt hat. Stimmt der Adressnachweis nicht, sperrt die Prüfung entweder echte Administratoren aus oder lässt jeden herein, der einen Header tippen kann. Beginne mit dem, was der Ursprung tatsächlich empfängt.
Was der Ursprung nach dem Tunnel tatsächlich empfängt
Wenn ein Browser die öffentliche Website über ein VPN erreicht, das auch Internetverkehr transportiert, übersetzt das Gateway die Verbindung, bevor sie hinausgeht. Die SaaS-Instanz sieht die öffentliche Egress-Adresse des Gateways, typischerweise eine Adresse oder einen kleinen Bereich, und sieht nie die Tunneladresse des Laptops. Deshalb scheitert das Aufnehmen von 10.90.0.42 in die Allowlist, und deshalb scheitert das Aufnehmen des gesamten RFC 1918 noch lauter: Letzteres lässt jedes private Netz herein, das dich erreichen kann. Die einzige Adresse, auf die sich eine Bedingung lohnt, ist die, die deine Organisation am Ausgang tatsächlich besitzt.
curl -s https://ifconfig.me
dig +short admin.example.com
Split-Tunneling bricht diese Annahme still. Trägt das VPN nur private Bürorouten, verlässt die Anfrage an den öffentlichen Admin-Hostnamen den lokalen ISP, und der Ursprung sieht eine Wohnadresse. Ein verbundenes VPN-Symbol beweist nichts über dieses konkrete Ziel, also teste das Ziel statt den Tunnel.
Halte inne und repariere das Routing, bevor du irgendeine Richtlinie schreibst, wenn die Egress-Adresse pro Benutzer variiert. Eine Bedingung, die nur einige Administratoren trifft, ist schlimmer als keine Bedingung, weil sie das Problem bis zu einem Vorfall verbirgt.
Vertraue nur dem Proxy, der die Adresse umschreibt
Die meisten öffentlichen Websites stehen hinter einem CDN oder Reverse-Proxy, also gehört die Socket-Adresse des Ursprungs zu diesem Frontend und nicht zum Besucher. Das Frontend leitet die ursprüngliche Adresse normalerweise in einem Header weiter, und dieser Header wird vom Angreifer kontrolliert, es sei denn, der Ursprung akzeptiert ihn nur von bekannten Proxys. Konfiguriere die Liste der vertrauenswürdigen Quellen ausdrücklich und mache den Ursprung von überall sonst unerreichbar. Ohne diese zweite Hälfte umgeht ein Angreifer den Proxy und sendet den Header direkt.
set_real_ip_from 192.0.2.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
curl -H 'X-Forwarded-For: 198.51.100.27' https://origin.example.com/admin
Dieselbe Überlegung gilt für das PROXY-Protokoll: Es ist nur vertrauenswürdig, wenn der Listener an eine Schnittstelle gebunden ist, die der Proxy erreichen kann und sonst niemand. Fehlender Adresskontext muss die geschützte Prüfung scheitern lassen, statt in eine Standardfreigabe durchzufallen. Ein fehlender Header ist kein Beleg für einen vertrauenswürdigen Pfad.
Hänge die Bedingung an jede geschützte Operation
Setze die Prüfung an die Autorisierungsgrenze, die jede geschützte Operation passiert, nicht in die Seite, die das Menü rendert. Routengruppen, Middleware oder eine Policy-Schicht funktionieren alle; eine Kopie pro Handler nicht, weil der Handler, den jemand im nächsten Quartal hinzufügt, sie nicht haben wird.
user = requireAuthenticatedSession()
requirePermission(user, "admin")
requireVpnEgress(verifiedClientAddress(request))
performProtectedOperation(user, request)
Dieselbe Grenze muss die JSON-API, Exporte, signierte Download-URLs und den WebSocket-Handshake abdecken, da keines davon verlangt, dass die HTML-Seite zuerst angefragt wird. Ein Download-Link, der erzeugt wurde, während das VPN aktiv war, bleibt danach gültig, es sei denn, der Download-Endpunkt prüft erneut. Langlebige Sitzungen brauchen ebenfalls eine Neubewertungsregel, sonst wird eine authentifizierte Anfrage zu einer dauerhaften Ausnahme. Standardverweigerung ist die einzige Einstellung, die Personalwechsel übersteht.
Gemeinsame Caches sind der andere Weg um die Prüfung herum. Ein Cache, der bereits eine geschützte Antwort hält, kann sie ausliefern, ohne den Ursprung zu kontaktieren, also markiere Admin-Antworten als privat und halte sie aus gemeinsamem Speicher heraus. Muss ein Cache sie ausliefern, muss die Zugriffsprüfung vor der Auslieferung laufen, was meist bedeutet, dass er überhaupt kein gemeinsamer Cache sein kann.
Teste die Umgehungen, die du gerade geschlossen hast
Übe die Matrix statt des glücklichen Pfads: ein Administrator durch das VPN, derselbe Administrator ohne es, ein Nicht-Administrator durch es und ein gefälschter Adress-Header. Ergänze eine Anfrage direkt an den Ursprung und eine Anfrage mit gecachter Antwort, denn diese beiden überspringen das Frontend vollständig.
curl -sI https://admin.example.com/export.csv
curl -s -H 'X-Forwarded-For: 198.51.100.27' https://origin.example.com/admin
curl -s https://admin.example.com/api/me -o /dev/null -w '%{http_code}\n'
Jede Anfrage sollte den Status zurückgeben, den die Richtlinie verspricht, und das Log sollte festhalten, welcher Adressnachweis verwendet wurde. Decke IPv6 separat ab, weil ein Dual-Stack-Ursprung eine andere Quellfamilie sehen kann als die getestete. Halte gewöhnliche Kundenoperationen außerhalb des VPN funktionsfähig, sonst wird die Änderung beim ersten Kundenbeschwerde zurückgenommen. Schreibe das erwartete Ergebnis für jede Zeile vor dem Lauf auf, damit ein überraschender Erfolg sichtbar wird.
Die Egress-Adresse belegt einen erlaubten Netzwerkpfad, nicht eine Person und kein verwaltetes Gerät. Behalte sie als eine Bedingung neben Authentifizierung und Berechtigung, und der Adminbereich bleibt eng, ohne das ganze Produkt zu einem reinen VPN-Dienst zu machen. Diese Trennung ist das Design, keine Einschränkung davon.