Zum Inhalt springen

Odoo 19 Community: Web RBL – Sperrliste für Angriffsverkehr auf den eigenen Webseiten

24. September 2026 durch
Odoo 19 Community: Web RBL – Sperrliste für Angriffsverkehr auf den eigenen Webseiten

Quellcode: github.com/Alex0176/odoo-web-rbl — AGPL-3, frei verwendbar.

Wer einen Odoo-Server im Internet betreibt, bekommt Besuch. Nicht gelegentlich, sondern ununterbrochen. Über siebzehn Tage haben wir auf unseren fünf Webseiten 731.297 Anfragen mitgeschrieben und ausgewertet. 110.511 davon waren keine Besucher, sondern automatisierte Suche nach Schwachstellen, Zugangsdaten und Konfigurationsdateien.

Dieser Beitrag beschreibt Web RBL, ein Open-Source-Modul für Odoo 19 Community, das diesen Verkehr erkennt, verbucht und abweist — und das die Sperrliste so veröffentlicht, dass eine Firewall sie unmittelbar verwenden kann. Alle Zahlen stammen aus dem Echtbetrieb.

Was Web RBL schützt — die Schutzwirkung im Einzelnen

Ein Abwehrmodul ist nur so viel wert wie das, was es messbar verhindert. Die Schutzwirkung liegt auf vier Ebenen.

1. Zugangsdaten bleiben unentdeckt

Die größte gemessene Angriffsklasse sucht nicht nach Lücken in Odoo, sondern nach liegengebliebenen Geheimnissen. Über siebzehn Tage:

  • 57.721 Anfragen nach .env-Dateien — dort stehen Datenbankkennwörter, API-Schlüssel und Sitzungsgeheimnisse
  • 5.535 Anfragen nach Konfigurationsdateien
  • 4.388 Anfragen nach Cloud-Zugangsdaten: credentials.json, service-account.json, firebase-adminsdk.json, rclone.conf, .git-credentials
  • 2.811 Anfragen nach .git-Verzeichnissen — wer eines findet, lädt den vollständigen Quellcode samt Historie herunter
  • 1.907 Anfragen nach Bauanweisungen wie .github/workflows/deploy.yml oder .gitlab-ci.yml, in denen Registraturen und Schlüsselnamen stehen

Entscheidend ist dabei nicht die Zahl der Anfragen, sondern die Zahl der verschiedenen Adressen: /credentials.json kam von 98 Adressen, /.git-credentials von 92. Das ist kein einzelner Scanner, sondern ein Standardrepertoire, das weltweit gleichzeitig läuft.

2. Anmeldeversuche laufen ins Leere — dauerhaft

Odoo bringt eine eigene Bremse gegen das Durchprobieren von Kennwörtern mit. Sie hat drei Grenzen, die im Odoo-Quelltext selbst dokumentiert sind: Der Zähler liegt im Arbeitsspeicher des Arbeitsprozesses und wird bei jedem Neustart zurückgesetzt, er verzögert nur statt zu sperren, und er zählt ausschließlich Versuche, die bis zur Kennwortprüfung durchkommen.

Web RBL setzt an denselben Stellen an, schreibt aber in die Datenbank. Damit gilt:

  • Der Stand überlebt jeden Neustart
  • Erfasst werden beide Wege: die Anmeldemaske /web/login und die Schnittstelle /xmlrpc/2/common
  • Erfasst werden auch Versuche, die nie bis zur Kennwortprüfung gelangen — etwa Anmeldungen ohne gültiges Sitzungsmerkmal
  • Ein gescheiterter Zugriff auf den Datenbankverwalter wird mitgezählt; das ist der schwerwiegendste Anmeldeversuch überhaupt

3. Der Angriff kostet den Server nichts mehr

Eine Sonde auf einen Pfad wie /@fs/../../.env war vor dem Modul teuer: Odoo sucht die Fehlerseite, rendert sie, stolpert beim Aufbau der Adresse über die Punkt-Segmente und scheitert daraufhin auch an der Fehlerseite der Fehlerseite. Zwei Stapelprotokolle je Sonde. Gemessen wurden 28.401 solcher Fehler in siebzehn Tagen, dazu 9.467 Folgefehler.

Web RBL greift in ir.http._match, also vor der Wegfindung. Die Antwort fällt ohne Vorlage, ohne Datenbankzugriff über die Sperrprüfung hinaus und ohne Protokollzeile.

4. Die Firewall wirft den Angreifer hinaus, bevor er ankommt

Die Sperrliste wird unter einer Adresse veröffentlicht, die HAProxy und OPNsense unmittelbar lesen können. Der Angreifer erreicht den Webserver damit gar nicht mehr — und auch keinen anderen Dienst auf demselben Host. Ein einmal als bösartig erkannter Zugriff schützt so rückwirkend die gesamte Maschine.

Drei Stufen: sperren, zählen, melden

Nicht jede Anfrage ins Leere ist ein Angriff. Web RBL unterscheidet deshalb drei Stufen, und die Stufe lässt sich je Muster umstellen, ohne den Code anzufassen.

StufeDie auslösende AnfrageFolge für die Adresse
sperrenwird abgewiesen24 Stunden gesperrt, nach drei auffälligen Tagen dauerhaft
zählenläuft durchnur verbucht, keine Sperre
meldenläuft durchverbucht mit Befundtext, wird nie gesperrt

Zusätzlich lässt sich je Muster eine Schwelle setzen: so viele Treffer desselben Musters, bevor gesperrt wird. Für Anmeldungen steht sie auf zehn, und der Grund ist eine Messung: Von neun gescheiterten Anmeldungen in siebzehn Tagen stammte die Mehrzahl von Kunden, die sich den Zugang selbst auf einem weiteren Gerät einrichteten und dabei die falsche Domain eintrugen — in einem Fall die eigene, nur mit Bindestrich statt Punkt.

Eine Sperre beim ersten Fehlversuch hätte damit nicht Angreifer getroffen, sondern Kunden bei der Einrichtung — und zwar genau dann, wenn sie ohnehin schon Mühe haben. Das ist der praktischste Grund für eine Schwelle, den wir kennen: Die ersten Fehlversuche einer Adresse sagen wenig darüber aus, wer dahintersteht. Erst die Beharrlichkeit tut es.

Wer dagegen weiterklopft, obwohl der Server bereits „bitte kurz warten" geantwortet hat, wird sofort gesperrt. Diese Meldung liest ein Mensch und wartet; wer sie ignoriert, liest sie nicht, weil ihn niemand liest. Ein eigenes Muster mit Schwelle null fängt genau diesen Fall ab, und es kann keinen Kollegen treffen: Dorthin gelangt nur, wer bereits zehn Fehlversuche hinter sich hat und danach weitermacht.

Welche Angriffe erkannt werden

Alle Muster sind gegen echten Verkehr geprüft. Die Zahl der verschiedenen Adressen steht bewusst daneben — sie zeigt, ob ein Muster einen einzelnen Scanner trifft oder ein verbreitetes Vorgehen.

AngriffsklasseAnfragenAdressen
.env-Abgriff57.721223
PHP-Sonden12.237256
Pfad-Traversal mit lohnendem Ziel10.04664
Konfigurationsdateien5.535114
Cloud-Zugangsschlüssel4.388152
WordPress-Sonden3.366385
.git-Abgriff2.811255
Odoo-Erkundung (Datenbankverwalter, Versionsabfrage)2.500213
KI-Werkzeugketten (/mcp, /api/fs/exec)2.45074
Bauanweisungen (CI/CD)1.90788
GraphQL-Endpunkte1.87871

Bemerkenswert ist die jüngste Klasse. /api/fs/exec wurde 369 mal von 54 verschiedenen Adressen angefragt — das ist kein Lesezugriff, sondern der Versuch, Befehle auszuführen. Solche Ziele gab es vor zwei Jahren nicht; sie stammen aus Schnittstellen neuer KI-Werkzeuge und Aufgabenwarteschlangen. Wer seine Abwehr nur auf WordPress und PHP ausrichtet, sieht davon nichts.

Fehlkonfigurationen melden statt sperren

Der häufigste Fall im Echtverkehr ist weder Angriff noch Besucher, sondern defekte Software, die den Webserver für etwas anderes hält:

  • 1.367 Aufrufe der Web-Schnittstelle eines QNAP-NAS — ein Sync-Client, dessen Ziel nicht mehr stimmt. Ein einziger Anschluss klopfte 962 mal an.
  • 65 Autodiscover-Abfragen — ein Outlook, das die Webdomain für seinen Exchange hält

Solche Adressen werden nie gesperrt. Eine Sperre behebt den Defekt nicht, sie verbirgt ihn — und trifft denjenigen, dessen Gerät ohnehin schon falsch eingestellt ist. Stattdessen entsteht ein Eintrag mit Befundtext und den betroffenen Domains, aus dem auf Wunsch automatisch ein Ticket wird: je Adresse genau eines, und wird es geschlossen und die Adresse fällt erneut auf, öffnet sich dasselbe Ticket wieder, statt dass ein zweites entsteht.

Erkannt werden QNAP, Synology, Exchange-Autodiscover, ActiveSync sowie WebDAV-, CalDAV- und CardDAV-Clients. Die Muster nennen dabei exakte Dateinamen und Verzeichnisse, niemals bloße Endungen: Im selben Verzeichnis /cgi-bin/ liegen die harmlosen Sync-Aufrufe direkt neben klassischen Sonden wie printenv.pl.

Die Freiliste: Adressen, die nie gesperrt werden

Der Preis eines Irrtums ist nicht bei allen Adressen gleich. Bei einem Scanner aus einem Rechenzentrum kostet ein Fehlalarm nichts. Bei der Gegenstelle eines Standorttunnels kostet er den Standort.

Deshalb gibt es eine zweite Liste, die vor der ersten steht: Adressen und Netze, die nie gesperrt werden. Sie schaltet dabei nichts stumm — wer darauf steht, wird weiterhin geprüft und verbucht, nur die Folge entfällt. Das ist der Unterschied zu einer Ausnahme in der Firewall: Die macht blind, diese macht nur geduldig.

Gefüllt wird sie täglich aus der Firewall selbst, damit ein neu eingerichteter Tunnel nicht darauf angewiesen ist, dass jemand an die Sperrliste denkt. Dabei gilt eine Regel, die wichtiger ist als der Abgleich: Eine leere Antwort löscht nie. Antwortet die Quelle nicht, leer oder unverständlich, bleibt die Liste unverändert. Eine Freiliste, die sich bei einer Störung selbst leert, nimmt im schlechtesten denkbaren Moment alle Tunnel mit — die Firewall ist nicht erreichbar, also sind auch ihre Gegenstellen nicht mehr geschützt.

Drei Schranken sorgen dafür, dass eine Freilisten-Adresse die ausgelieferte Sperrliste nicht erreichen kann: Sie wird nicht gesperrt, bestehende Sperren werden beim Aufnehmen sofort gelöst, und der Endpunkt filtert zusätzlich. Die dritte ist Absicht — aus dieser Liste baut eine Firewall unbesehen Regeln.

Pflichtangaben und automatisierte Datensammler

Das Impressum ist keine gewöhnliche Seite. Es muss für Menschen erreichbar bleiben, denn eine Sperre darauf schafft genau den Verstoß, den ein Sammler sucht. Zugleich ist es die Seite, auf der Name und Anschrift stehen — und damit das Ziel maschineller Ernte.

Bei der österreichischen Abmahnwelle wegen eingebundener Google-Schriften zeigten die Protokolle, dass die Schreiben nicht aus Einzelbesuchen stammten, sondern aus einem automatisierten Rundumschlag: verschiedene, nicht zusammenhängende Hosts im Abstand von Millisekunden.

Web RBL löst das durch Herabstufung statt Ausnahme. Der kanonische Pfad /impressum trifft auf gar kein Muster und bleibt immer erreichbar. Fremde Schreibweisen wie /impressum.php — die es auf einer Odoo-Seite nicht geben kann — werden gemeldet, und wer die maschinelle Ernte nicht hinnehmen will, stellt einen Parameter um.

sitemap und robots sind davon ausgenommen und grundsätzlich nicht sperrbar: Sie enthalten keine personenbezogene Angabe, und sie zu holen ist die Aufgabe jedes Suchmaschinen-Crawlers.

Domain und Kennung: was im Zugriffsprotokoll fehlt

Das Zugriffsprotokoll von werkzeug schreibt weder den angesprochenen Host noch die Kennung des Aufrufers mit. Odoo bekommt beide selbstverständlich — ohne den Host könnte es bei mehreren Webseiten gar nicht die richtige auswählen. Nachlesen kann man es hinterher aber nicht.

Web RBL hält beides je Treffer fest. Das beantwortet zwei Fragen, die sich sonst nicht beantworten lassen: welche Webseite eine Fehlkonfiguration anspricht — und damit, welchem Kunden die Domain gehört — und ob eine Adresse eine Seite besucht oder alle.

Wie viel die Kennung ausmacht, zeigte eine Auswertung auf einer unserer Webseiten: Über siebzig Prozent des gesamten Verkehrs entfielen dort auf einen einzigen Aufrufer, verteilt über mehr als hundert Adressen. Ohne die Kennung hätte das wie ein verteilter Scraper ausgesehen. Es war GPTBot, der Crawler von OpenAI — er fragte immer wieder nach robots.txt und verhielt sich vollkommen korrekt. Eine Sperre wäre hier sogar schädlich gewesen: Sie hätte die Seite unsichtbar und ohne Weg zurück aus der Indexierung genommen.

Die Sicherheitsaspekte im Einzelnen

1. Die Proxy-Erkennung — die gefährlichste Stelle überhaupt

Läuft Odoo hinter einem Reverse Proxy und ist proxy_mode falsch gesetzt, sieht das Modul bei jeder Anfrage dieselbe Adresse: die des Proxys. Eine Sperre würde dann alle Besucher gleichzeitig aussperren.

Deshalb prüft Web RBL vor jeder Sperre, ob die Adressbestimmung verlässlich ist. Es verlangt proxy_mode zusammen mit einer Weiterleitungs-Kopfzeile, verweigert die Arbeit, wenn eine Weiterleitung ohne proxy_mode ankommt, und verweigert sie ebenso bei mehr als einem Zwischenproxy — dann wäre die ermittelte Adresse die eines Proxys und nicht die des Besuchers. Im Zweifel wird nicht gesperrt.

2. Eigene Netze niemals

Private Adressbereiche, Loopback, Link-Local und CGNAT sind fest ausgenommen. Sie können unter keinen Umständen auf der Liste landen, auch nicht von Hand.

3. Ein eigener Fehler darf die Webseite nicht mitnehmen

Die gesamte Prüfung läuft in einer Absicherung, die jeden Fehler abfängt: ein Datenbankfehler, ein kaputtes Muster, eine fehlende Tabelle. Was hier schiefgeht, wird protokolliert, und die Anfrage läuft unverändert weiter. Ein Schutzmodul, das bei einem eigenen Fehler die Webseite mitnimmt, ist schlimmer als gar keines.

4. Beobachten vor Sperren

Nach der Installation ist das Sperren abgeschaltet. Sonden werden abgewiesen und verbucht, gewöhnliche Anfragen gelisteter Adressen laufen aber durch. So lässt sich einige Tage mitlesen, wer tatsächlich auf der Liste landet, bevor jemand ausgesperrt wird.

5. Enge Muster statt breiter Netze

Ein falsch erkannter Besucher ist teurer als eine übersehene Sonde. Jedes Muster trägt deshalb seine Stufe, und sie ist je Muster umstellbar. Eine Dateiendung allein genügt selten: Bei .php stehen 14.012 echte Sonden gegen eine Handvoll Altlinks, bei .asp ist das Verhältnis umgekehrt. Solche Entscheidungen gehören gemessen, nicht geschätzt.

6. Eine Freigabe von Hand bleibt bestehen

Wer eine Adresse freigibt, hatte einen Grund. Ein weiterer Treffer setzt diese Entscheidung nicht stillschweigend außer Kraft.

7. Die Liste ist geschützt, aber kein Geheimnis

Der Endpunkt verlangt ein Token und antwortet ohne gültiges Token mit 404, nicht mit 403 — die Existenz der Adresse wird damit gar nicht erst bestätigt. Der Vergleich läuft zeitkonstant. Die Liste selbst enthält nichts Vertrauliches: Sie besteht aus Adressen, die von sich aus bei uns angeklopft haben.

8. Keine Geheimnisse in der Buchhaltung

Bei gescheiterten Anmeldungen wird der versuchte Benutzername vermerkt, niemals das Kennwort. Beim Datenbankverwalter wird aus den übergebenen Werten gar nichts gelesen: Dort steht an vorderster Stelle das Hauptkennwort, und ein Eintrag in einer Sperrliste wandert in jede Datenbanksicherung.

9. Der Köder verrät nichts Verwertbares

Optional beantwortet Web RBL Sonden mit erfundenem Inhalt, der einen eindeutigen Kanarienwert enthält. Wer diesen Wert später abruft, hat die gefälschte Antwort gelesen und daraufhin gehandelt — ein Fehlalarm ist dabei ausgeschlossen. Die Köder enthalten keine verwertbaren Angaben, keine echten Pfade und keine gültigen Zugangsdaten. Ausgeliefert wird diese Funktion abgeschaltet, denn sie ändert das Verhalten nach außen sichtbar.

Einbindung in Firewall und Reverse Proxy

Die Sperrliste steht unter einer eigenen Adresse zur Verfügung, wahlweise als einfache Liste oder als JSON mit Zustand, Trefferzahl und Frist. Eine zweite Liste führt ausschließlich die Adressen der schärfsten Stufe.

Damit lässt sich die Abwehr an die Kante ziehen: HAProxy weist die Anfrage ab, bevor sie Odoo erreicht, und OPNsense verwirft die Pakete, bevor sie den Webserver erreichen. Ein Angreifer, der einmal erkannt wurde, kommt damit an keinen Dienst des Hosts mehr heran — auch nicht an den Mailserver.

Was das Modul nicht kann

Es ersetzt keine Firewall und keine Web Application Firewall. Es erkennt bekannte Sondierungsmuster in Pfaden und gescheiterte Anmeldungen — nicht Angriffe auf Formulare, nicht Einschleusungsversuche in Parameter, nicht den Missbrauch gültiger Zugangsdaten.

Es sieht außerdem nur, was über HTTP zurückkommt. Was ein Angreifer mit erbeuteten Datenbank- oder Postfachzugängen anstellt, bleibt unsichtbar — und genau deshalb sind die Kanarienwerte Pfade und keine Zugangsdaten.

Und es ersetzt keine Sorgfalt: Ein Modul, das .env-Sonden abweist, macht eine versehentlich ausgelieferte .env-Datei nicht ungefährlich.

Verfügbarkeit

Web RBL steht unter der AGPL-3 öffentlich zur Verfügung und läuft bei uns produktiv auf fünf Webseiten:

github.com/Alex0176/odoo-web-rbl

Das Modul setzt Odoo 19 Community voraus und hat keine Abhängigkeiten außer base und web. Die Ticketanbindung ist optional und benötigt kein bestimmtes Ticketsystem; ohne ein solches passiert schlicht nichts.

Fragen, Anmerkungen und Fehlerberichte nehmen wir gerne entgegen — am liebsten als Issue auf GitHub.