Ein Monitoring-Dienst tut etwas, das auf den ersten Blick wie ein Angriff aussieht: Er ruft Adressen auf, die ein Fremder eingetragen hat, und zwar von seinem eigenen Server aus. Für öffentliche Websites ist das genau der Zweck. Bei internen Adressen wird es zum Problem.
Das Problem
Trägt jemand statt einer Website eine interne Adresse ein, zum Beispiel die des eigenen Rechners (localhost), eines Dienstes im Rechenzentrumsnetz oder die Adresse 169.254.169.254, unter der Cloud-Anbieter ihre Metadaten ausliefern, dann fragt unser Server dort an. Wir zeigen Status, Antwortzeit und Fehlermeldung an. Daran lässt sich ablesen, was hinter der Firewall läuft, obwohl der Anfragende nie Zugriff darauf hatte. Dieser Angriff heißt Server-Side Request Forgery, kurz SSRF, und steht in der OWASP-Dokumentation als eigenes Thema.
Beim Review unseres Checkers haben wir genau das festgestellt: Er prüfte jede eingetragene Adresse, auch interne. In der Entwicklungsumgebung ließ sich so ein Dienst im Docker-Netz abfragen. Das haben wir vor dem Start des Dienstes behoben.
Was Uptime jetzt blockiert
- Loopback-Adressen wie 127.0.0.1 und ::1.
- Private Netze (10/8, 172.16/12, 192.168/16) und ihr IPv6-Gegenstück.
- Link-Local-Adressen, darunter die Cloud-Metadaten-Adresse.
- Die Adressen für Carrier-Grade NAT (100.64/10), die zum Beispiel Tailscale nutzt.
- Multicast, nicht spezifizierte, reservierte und einige Übergangsbereiche von IPv6.
Warum die Prüfung an der Verbindung sitzt
Der naheliegende Weg wäre, die eingegebene Adresse beim Speichern zu prüfen. Das reicht nicht, denn ein Hostname kann auf etwas anderes zeigen als beim Speichern. Wer die DNS-Einträge einer eigenen Domain kontrolliert, kann sie nach der Prüfung auf eine interne Adresse umstellen (DNS-Rebinding). Auch Umleitungen können zu internen Zielen führen.
Deshalb sitzt unsere Prüfung dort, wo die Verbindung entsteht:
- Der Hostname wird aufgelöst und jede Adresse der Antwort geprüft. Enthält die Antwort auch nur eine unzulässige Adresse, wird nichts verbunden.
- Verbunden wird nur mit der geprüften numerischen Adresse. Es gibt keine zweite Namensauflösung, die ein Angreifer beeinflussen könnte.
- IPv4-Adressen in IPv6-Schreibweise werden zuerst zurückgerechnet, damit sie sich nicht an der Prüfung vorbeischmuggeln.
- Schlägt die Namensauflösung fehl oder kommt keine Adresse zurück, bleibt es bei einem Fehler. Der Schutz öffnet im Zweifel nichts.
- Dieselbe Prüfung gilt für HTTP, TCP und Ping.
Für HTTP kommt hinzu: Der Checker nutzt keinen Proxy aus der Umgebung, der die Prüfung umgehen könnte. Host-Header und TLS-Name bleiben die ursprünglichen, damit Zertifikate weiter richtig geprüft werden. Umleitungen folgt der Checker nicht, eine 3xx-Antwort zählt wie bisher als erreichbar. Ein Weiterleiten auf ein internes Ziel führt also nirgendwohin.
Was beim Review noch auffiel
Ein unabhängiges Review fand zwei Lücken: einen alten IPv6-Adressbereich für lokale Netze und ein fehlendes Zeitlimit für Ausweichadressen. Beide wurden zuerst mit einem fehlschlagenden Test nachgestellt und dann behoben. Zusätzlich gibt der Dialer sich selbst ein Gesamtzeitlimit, weil Go bei diesem Schritt die Frist der Anfrage nicht weitergibt.
Und die Entwicklung?
Damit lokale Testdienste weiter prüfbar sind, gibt es eine Ausnahme, die nur in der Entwicklungsumgebung gilt. In jeder anderen Umgebung lehnt der Dienst den Start ab, wenn sie gesetzt ist. Derselbe Schutz gilt auch für ausgehende Webhooks, weil auch deren Adressen Kundeneingaben sind.
Was das für dich heißt
Uptime kann Dienste im öffentlichen Internet prüfen, aber keine, die nur in deinem privaten Netz erreichbar sind. Für interne Systeme brauchst du einen öffentlich erreichbaren Statusendpunkt, der nur das Nötige verrät. Das ist ausdrücklich so gewollt: Ein Monitoring-Dienst, der in dein Netz hineinschauen könnte, könnte es auch für jeden anderen tun.



