Broncode: github.com/Alex0176/odoo-web-rbl — AGPL-3, vrij te gebruiken.
Wie een Odoo-server op internet beheert, krijgt bezoek. Niet incidenteel, maar onafgebroken. Over zeventien dagen hebben we op onze vijf websites 731.297 verzoeken geregistreerd en geanalyseerd. 110.511 daarvan waren geen bezoekers, maar geautomatiseerd zoeken naar kwetsbaarheden, inloggegevens en configuratiebestanden.
Dit bericht beschrijft Web RBL, een open-sourcemodule voor Odoo 19 Community die dit verkeer herkent, beoordeelt, vastlegt en afwijst — en die de blokkeerlijst als RBL-lijst publiceert, dus in het formaat dat firewalls en reverse proxy's rechtstreeks lezen. Alle cijfers komen uit de praktijk.
Wat de module kan — de functies in overzicht
| Functie | Wat ze doet | Levering |
|---|---|---|
| Patroonherkenning | Herkent sonderingen aan pad en extensie: .env, .git, configuratiebestanden, cloudsleutels, CI/CD-bouwinstructies, WordPress, PHP, pad-traversal, databasebeheerders, GraphQL, opdrachtuitvoering via /api/fs/exec en vergelijkbare interfaces | blokkeren |
| Drie niveaus per patroon | blokkeren, tellen of melden — per patroon aan te passen, zonder code | per patroon |
| Drempels | Zoveel treffers van hetzelfde patroon voordat wordt geblokkeerd; voor aanmeldingen tien | 10 bij aanmelding |
| Aanmeldingsafweer | Mislukte aanmeldingen via het formulier en XML-RPC/JSON-RPC, mislukte sessiecontroles, toegang tot de databasebeheerder — in de database, niet in het werkgeheugen | aan |
| Botherkenning bij de aanmelding | Wie de wachtmelding na tien mislukte pogingen negeert en blijft kloppen, wordt direct geblokkeerd | blokkeren |
| Gedragsherkenning | Adressen die in vijf minuten twintig foutpagina's en nauwelijks een treffer genereren — dus raden in plaats van lezen | melden |
| Beoordeling 0–100 | Hoe zeker is het dat achter het adres een aanvaller zit? Uit de ernst van het patroon, het aantal verschillende patronen, opvallende dagen, getroffen domeinen en aantal treffers — met een toelichting in gewone taal | aan |
| Aanmeldblokkade op basis van beoordeling | Vanaf een instelbare beoordeling is aanmelden verboden, de website blijft leesbaar | vanaf 40 |
| Vermoeden van gestolen inloggegevens | Een geslaagde aanmelding vanaf een opvallend adres wordt gemeld en op verzoek als taak toegewezen — één keer per adres en per dag | aan |
| Dreigingslijsten | Tor-exitnodes, Spamhaus DROP, FireHOL Level 1 en blocklist.de zijn vooraf geconfigureerd; elke andere RBL-lijst is per adres toe te voegen, dagelijkse vergelijking, per lijst een eigen niveau | melden |
| Geen toegang tot de aanmelding | Het vierde niveau voor lijsten en landen: website leesbaar, aanmeldscherm en interfaces dicht — het passende antwoord op Tor | Optie |
| Herkomstland | Land per treffer en adres via GeoLite2; de database wordt door de module zelf bijgewerkt met een gratis licentiesleutel | tonen |
| Landregels | Blokkeren, geen toegang tot de aanmelding, melden of uitdrukkelijk vrij — per land, bewust zonder standaardwaarde | geen |
| Foutieve configuraties | QNAP, Synology, Exchange Autodiscover, ActiveSync, WebDAV/CalDAV/CardDAV worden herkend, nooit geblokkeerd en met bevinding en betrokken domein in een werklijst geplaatst | melden |
| Ticket per adres | Van een bevinding wordt op verzoek een ticket gemaakt — precies één per adres; een gesloten ticket wordt heropend in plaats van verdubbeld | uit |
| Verplichte pagina’s en verzamelaars | Het canonieke pad van het impressum blijft altijd bereikbaar; geautomatiseerd uitproberen van afwijkende schrijfwijzen wordt herkend en op verzoek geblokkeerd | melden |
| Vrijlijst | Adressen en netwerken die nooit worden geblokkeerd; wordt dagelijks aangevuld vanuit de firewall (VPN-tegenstations) en uit de gepubliceerde adresbereiken van Googlebot en Bingbot | aan |
| Klanttoewijzing | Een treffer uit het netwerk van een klant wordt aan die klant toegewezen — op basis van de vrijlijst, nooit op de gok | aan |
| Domein en identificatie per treffer | Welke website werd aangesproken, met welke user-agent — beide ontbreken in het toegangslogboek | aan |
| Analyse | Diagram en draaitabel over alle treffers: per patroon, dag, domein, land, adres | aan |
| Lokaas | Sondes krijgen verzonnen antwoorden met een kanariewaarde; wie die later opvraagt, heeft ze gelezen | uit |
| RBL-levering | De blokkeerlijst als kale adreslijst of JSON op een eigen, met een token beveiligd adres — voor HAProxy, OPNsense en elke firewall die URL-lijsten inleest | aan |
Alles wat met melden, uit of optie wordt geleverd, is bewust zo: wie een blokkade activeert, moet dat doen omdat hij een paar dagen heeft meegekeken, wie erin trapt — niet omdat de standaardinstelling het zo wilde.
De analyse: treffers per patroon over zeven dagen. De hoogste balk is het zoeken naar .env-bestanden.
RBL-lijsten: een gestandaardiseerde manier om blokkades te leveren
RBL staat voor Real-time Blackhole List. De term komt uit de mailwereld, waar Spamhaus en anderen sinds de jaren negentig lijsten van kwaadaardige afzenderadressen publiceren. Het principe is uiterst eenvoudig en juist daarom zo wijdverbreid: één adres per regel, via HTTP op te halen, regelmatig opnieuw geladen. Geen formaat dat je eerst moet parsen, geen interface waarvoor je een tool nodig hebt.
Vrijwel elke firewall en elke reverse proxy kan zo’n lijst inlezen en er regels van maken. De fabrikanten noemen dat verschillend, het mechanisme is overal hetzelfde:
- OPNsense en pfSense — URL Table Alias: adreslijst via HTTP laden, als alias in firewallregels gebruiken, bijwerken per uur of per dag
- HAProxy — ACL-bestanden en maps:
src -f sperrliste.txtin eenhttp-request deny-regel, herlaadbaar via de runtime-API zonder herstart - nginx — geo-module met ingesloten adresbestand, of
deny-instructies uit een gegenereerdinclude-bestand - Fortinet FortiGate — External Block List resp. Threat Feed: een URL waaruit de firewall een IP-lijst haalt en die in beleidsregels gebruikt
- Palo Alto Networks — External Dynamic List (EDL): hetzelfde principe, als apart objecttype in het beveiligingsbeleid
- Check Point — Custom Intelligence Feeds en IP Block Lists via een URL
- Cisco Secure Firewall (Firepower) — Security Intelligence Feeds met eigen lijstbronnen
- Sophos Firewall — Third-Party Threat Feeds: adreslijsten van een URL als bron voor blokkeerregels
- Juniper SRX — Dynamic Address Entries uit feeds
- MikroTik RouterOS — Address Lists, met een script en
fetchgevuld vanaf een URL - CrowdSec — eigen lijsten als bron voor de bouncers op elk ondersteund systeem
Precies in dit formaat levert Web RBL zijn blokkeerlijst. De firewall weigert de pakketten voordat ze de webserver bereiken — en daarmee ook elke andere poging van hetzelfde adres, bijvoorbeeld op de mailserver of de VPN-gateway.
Beide richtingen, maar op de juiste plek
De route werkt ook omgekeerd: in Web RBL kan elke willekeurige RBL-lijst worden toegevoegd — een URL, een niveau, klaar. Tor-exitnodes, Spamhaus DROP, FireHOL en blocklist.de zijn vooraf geconfigureerd, meer komen er met drie klikken bij. De module splitst elke lijst op in adresbereiken en controleert elk verzoek daartegen, in enkele microseconden.
En toch: het is zinvoller om externe lijsten op de firewall daarvóór te gebruiken. Om drie redenen. De firewall ziet alle diensten, niet alleen HTTP — een adres van de Spamhaus-lijst moet ook bij de mailserver en de VPN stranden. Hij weigert op pakketniveau, voordat er ook maar een verbinding tot stand komt, en kost de applicatieserver daardoor niets. En hij is de plek waar dergelijke lijsten sowieso worden beheerd; een tweede kopie in de applicatie is een tweede plek die kan verouderen.
Waar de lijsten in de module dan nog goed voor zijn: voor wat een firewall niet kan. Die kent geen aanmeldscherm. Web RBL kan een adres van de Tor-lijst de toegang tot de aanmelding weigeren en de website toch leveren — wie anoniem wil lezen, mag dat; wie anoniem wachtwoorden wil uitproberen, niet. En het kan een geslaagde aanmelding vanaf een adres op de lijst als verdacht geval melden. Beide vereisen de lijst op de plek waar de aanmelding plaatsvindt.
Beoordeling in plaats van onderbuikgevoel
Een adres dat één keer naar /wp-login.php heeft gevraagd,
is iets anders dan een adres dat op twee dagen met vijf verschillende
patronen over drie domeinen is gegaan. Web RBL rekent dat om in een
score van 0 tot 100 — op basis van wat het zelf
heeft gezien, zonder externe dienst en zonder query naar buiten.
Een vermelding: 99 treffers, score 84, en de motivering in duidelijke taal — zwaarste patroon, vijf verschillende ernstige patronen, twee opvallende dagen, meer dan twintig treffers.
De score bepaalt twee dingen. Vanaf een instelbare waarde is de aanmelding verboden — de website blijft leesbaar, maar wie al naar toegangsgegevens heeft gezocht, krijgt geen kans om gevonden gegevens uit te proberen. En een geslaagde aanmelding vanaf een adres met een score wordt gemeld: dan heeft iemand niet meer geraden, maar geweten. Ofwel was de bevoegde gebruiker onderweg, ofwel zijn de toegangsgegevens kwijtgeraakt — de module beslist dat niet, het legt het voor aan iemand die kan navragen. Het wachtwoord zelf wordt daarbij nergens aangeraakt.
De blokkeerlijst, gefilterd op score vanaf 40: aantal treffers, opvallende dagen, getroffen domeinen en het laatste pad per adres.
Wat Web RBL beschermt — de beschermende werking in detail
1. Toegangsgegevens blijven onontdekt
De grootste gemeten aanvalsklasse zoekt niet naar kwetsbaarheden in Odoo, maar naar achtergebleven geheimen. Over zeventien dagen:
- 57.721 verzoeken om
.env-bestanden — daarin staan databasewachtwoorden, API-sleutels en sessiegeheimen - 5.535 verzoeken om configuratiebestanden
- 4.388 verzoeken om cloudtoegangsgegevens:
credentials.json,service-account.json,firebase-adminsdk.json,rclone.conf,.git-credentials - 2.811 verzoeken om
.git-mappen — wie er een vindt, downloadt de volledige broncode inclusief historie - 1.907 verzoeken om buildinstructies zoals
.github/workflows/deploy.ymlof.gitlab-ci.yml, waarin registries en sleutelnamen staan
Doorslaggevend is daarbij niet het aantal verzoeken, maar het aantal
verschillende adressen: /credentials.json kwam
van 98 adressen, /.git-credentials van 92. Dat is geen
enkele scanner, maar een standaardrepertoire dat wereldwijd
gelijktijdig draait.
2. Aanmeldpogingen lopen dood — blijvend
Odoo heeft een eigen rem tegen het uitproberen van wachtwoorden. Die heeft drie beperkingen, die in de Odoo-broncode zelf gedocumenteerd zijn: de teller staat in het werkgeheugen van het werkproces en wordt bij elke herstart gereset, hij vertraagt alleen in plaats van te blokkeren, en hij telt uitsluitend pogingen die tot aan de wachtwoordcontrole doorkomen.
Web RBL grijpt op dezelfde plekken in, maar schrijft naar de database. Daardoor geldt:
- De stand overleeft elke herstart en geldt over alle werkprocessen heen
- Beide routes worden vastgelegd: het aanmeldscherm
/web/loginen de interfaces/xmlrpc/2/commonen/jsonrpc - Ook pogingen die nooit tot de wachtwoordcontrole komen worden vastgelegd — bijvoorbeeld aanmeldingen zonder geldig sessiekenmerk
- Een mislukte toegang tot de databasebeheerder wordt meegeteld; dat is de ernstigste aanmeldpoging die er is
De drempel voor aanmeldingen staat op tien, en de reden is een meting: van negen mislukte aanmeldingen in zeventien dagen kwam de meerderheid van klanten die zelf de toegang op een ander apparaat instelden en daarbij het verkeerde domein invoerden — in één geval hun eigen domein, maar met een streepje in plaats van een punt. Een blokkade bij de eerste mislukte poging had dus niet aanvallers getroffen, maar klanten bij de installatie.
Wie daarentegen blijft aankloppen, hoewel de server al met “een ogenblik geduld” heeft geantwoord, wordt onmiddellijk geblokkeerd. Die melding leest een mens en die wacht; wie haar negeert, is een programma. Een eigen patroon met drempel nul vangt precies dit geval op, en het kan geen collega treffen: daar komt alleen terecht wie al tien mislukte pogingen achter de rug heeft en daarna doorgaat.
3. De aanval kost de server niets meer
Een sonde op een pad als /@fs/../../.env was vóór
de module duur: Odoo zoekt de foutpagina, rendert die, struikelt
bij het opbouwen van het adres over de puntsegmenten en faalt
vervolgens ook op de foutpagina van de foutpagina. Twee
stacktraces per sonde. Gemeten werden 28.401 van dergelijke fouten
in zeventien dagen, plus 9.467 vervolgfouten.
Web RBL grijpt in bij ir.http._match, dus vóór de
routering. Het antwoord komt zonder sjabloon, zonder databasetoegang
buiten de blokkadecontrole om en zonder logregel. De controle
tegen vrijlijst, dreigingslijsten en landregels loopt vanuit de
cache over gesorteerde adresbereiken — enkele
microseconden, zelfs bij meer dan dertigduizend bereiken.
4. De firewall gooit de aanvaller eruit voordat hij aankomt
De blokkeerlijst wordt als RBL-lijst gepubliceerd, die HAProxy en OPNsense rechtstreeks inlezen. De aanvaller bereikt de webserver daarmee helemaal niet meer — en ook geen andere dienst op dezelfde host. Eén keer als kwaadaardig herkende toegang beschermt zo met terugwerkende kracht de hele machine.
Drie niveaus: blokkeren, tellen, melden
Niet elk verzoek in het niets is een aanval. Web RBL onderscheidt daarom drie niveaus, en het niveau is per patroon aan te passen, zonder de code aan te raken.
| Niveau | Het uitlokkende verzoek | Gevolg voor het adres |
|---|---|---|
| blokkeren | wordt geweigerd | 24 uur geblokkeerd, na drie opvallende dagen permanent |
| tellen | gaat door | alleen geboekt, geen blokkade |
| melden | gaat door | geboekt met bevindingstekst, wordt nooit geblokkeerd |
Voor dreigingslijsten en landen is er een vierde: geen toegang tot de aanmelding. De website blijft leesbaar, aanmeldscherm en interfaces zijn dicht. Dat is de middenweg voor alles wat verdacht is, maar niet kwaadaardig hoeft te zijn — Tor, een datacenterbereik, een land zonder klanten.
Welke aanvallen worden herkend
Alle patronen zijn getoetst aan echt verkeer. Het aantal verschillende adressen staat bewust ernaast — het laat zien of een patroon een enkele scanner treft of een wijdverbreide werkwijze.
| Aanvalsklasse | Verzoeken | Adressen |
|---|---|---|
.env-afhandeling | 57.721 | 223 |
| PHP-sondes | 12.237 | 256 |
| Padtraversal met een lonend doel | 10.046 | 64 |
| Configuratiebestanden | 5.535 | 114 |
| Cloudtoegangssleutels | 4.388 | 152 |
| WordPress-sondes | 3.366 | 385 |
.git-afhandeling | 2.811 | 255 |
| Odoo-verkenning (databasebeheerder, versieopvraging) | 2.500 | 213 |
AI-toolketens en opdrachtuitvoering (/mcp, /api/fs/exec) | 2.450 | 74 |
| Buildinstructies (CI/CD) | 1.907 | 88 |
| GraphQL-endpoints | 1.878 | 71 |
Opmerkelijk is de jongste klasse. /api/fs/exec
werd 369 keer door 54 verschillende adressen opgevraagd — dat is
geen leestoegang, maar een poging om opdrachten uit te voeren. Zulke
doelen bestonden twee jaar geleden niet; ze komen uit interfaces
van nieuwe AI-tools en taakwachtrijen. Wie zijn verdediging alleen
op WordPress en PHP richt, ziet hier niets van. In de
score weegt deze klasse dan ook zwaar.
Dreigingslijsten en herkomstland
Vier lijsten, 32.851 adresbereiken, alle op “alleen melden”. Elke andere lijst is een adres en een niveau.
Een externe lijst is een bewering die iemand anders
doet, om redenen die wij niet kennen, over verkeer dat wij
nooit hebben gezien. Ze kan onjuist zijn, verouderd of voor een
ander doel bedoeld: blocklist.de verzamelt vooral
adressen die elders SSH-aanmeldingen hebben uitgeprobeerd, en dat
zegt weinig over een webserver. Daarom houdt Web RBL externe lijsten
gescheiden van de eigen blokkeerlijst, en daarom is de standaardwaarde
melden. En de eigen vrijlijst wint altijd: een klant die
wij kennen, weegt zwaarder dan het oordeel van een derde.
Het herkomstland staat bij elke treffer en elk adres. Voor de beoordeling is het onmisbaar — een aanmeldpoging uit het eigen land om tien uur ’s ochtends is iets anders dan een poging uit een land zonder één enkele klant. Voor algemeen buitensluiten is het weinig geschikt, en dat zeggen de eigen cijfers: de aanvallers in onze lijst kwamen overwegend uit cloudbereiken in België, Finland en Nederland. Een blokkade voor alles buiten het Duitstalige gebied had hen niet getroffen — wel eigen medewerkers op vakantie en klanten op zakenreis.
Landregels worden leeg geleverd, en de weergave zegt waarom.
Foutieve configuraties melden in plaats van blokkeren
Het meest voorkomende geval in echt verkeer is geen aanval en geen bezoeker, maar defecte software die de webserver voor iets anders houdt:
- 1.367 aanroepen van de webinterface van een QNAP-NAS — een synchronisatieclient waarvan het doel niet meer klopt. Eén enkele aansluiting klopte 962 keer aan.
- 65 Autodiscover-verzoeken — een Outlook die het webdomein voor zijn Exchange houdt
Zulke adressen worden nooit geblokkeerd. Een blokkade verhelpt het defect niet, ze verbergt het — en treft degene wiens apparaat al verkeerd is ingesteld. In plaats daarvan ontstaat een vermelding met bevindingstekst en de betrokken domeinen, waaruit op verzoek automatisch een ticket wordt: per adres precies één, en wordt het gesloten en valt het adres opnieuw op, dan wordt hetzelfde ticket heropend in plaats van dat er een tweede ontstaat.
Herkend worden QNAP, Synology, Exchange Autodiscover, ActiveSync
en WebDAV-, CalDAV- en CardDAV-clients. De patronen noemen daarbij
exacte bestandsnamen en mappen, nooit kale extensies:
In dezelfde map /cgi-bin/ staan de onschuldige
synchronisatieaanroepen direct naast klassieke sondes zoals
printenv.pl.
De vrijlijst: adressen die nooit worden geblokkeerd
De prijs van een vergissing is niet bij alle adressen gelijk. Bij een scanner uit een datacenter kost een valse melding niets. Bij het tegenstation van een locatietunnel kost het de locatie.
Daarom is er een tweede lijst, die vóór de eerste staat: adressen en netwerken die nooit worden geblokkeerd. Ze zet daarbij niets op stil — wie erop staat, wordt nog steeds gecontroleerd en geboekt, alleen het gevolg vervalt. Dat is het verschil met een uitzondering in de firewall: die maakt blind, deze maakt alleen geduldig.
Ze wordt dagelijks gevuld uit twee bronnen: uit de firewall zelf met alle VPN-tegenstations, zodat een nieuw ingerichte tunnel er niet van afhangt dat iemand aan de blokkeerlijst denkt — en uit de gepubliceerde adresbereiken van Google en Microsoft voor hun crawlers. Alleen zo is een echte Googlebot te onderscheiden van een scanner die zich zo noemt. Zoekmachines mogen nooit worden geblokkeerd; wie ze buitensluit, haalt zijn site zonder terugweg uit de indexering.
Daarbij geldt een regel die belangrijker is dan de vergelijking: Een leeg antwoord wist nooit. Antwoordt de bron niet, leeg of onbegrijpelijk, dan blijft de lijst ongewijzigd. Een vrijlijst die zichzelf bij een storing leegmaakt, neemt op het slechtst denkbare moment alle tunnels mee.
Heeft een vermelding op de vrijlijst een klant, dan wordt elke treffer uit diens netwerk aan die klant toegewezen. Een foutieve configuratie heeft daarmee direct een aanspreekpunt, zonder dat iemand adressen hoeft op te zoeken.
Verplichte gegevens en geautomatiseerde gegevensverzamelaars
Het impressum is geen gewone pagina. Het moet voor mensen bereikbaar blijven, want een blokkade daarop creëert precies de overtreding die een verzamelaar zoekt. Tegelijk is het de pagina waarop naam en adres staan — en daarmee het doelwit van machinale oogst.
Bij de Oostenrijkse golf van waarschuwingsbrieven over ingesloten Google-lettertypen toonden de logboeken dat de brieven niet uit enkele bezoeken voortkwamen, maar uit een geautomatiseerde bulkactie: verschillende, niet met elkaar samenhangende hosts met een tussenpoos van milliseconden.
Web RBL lost dat op door terugzetten in plaats van uitzondering. Het
canonieke pad /impressum valt onder geen enkel patroon en
blijft altijd bereikbaar. Afwijkende schrijfwijzen zoals
/impressum.php — die op een Odoo-pagina niet
kunnen bestaan — worden gemeld, en wie de machinale oogst
niet wil accepteren, zet één parameter om.
sitemap en robots zijn hiervan uitgezonderd
en in beginsel niet te blokkeren: ze bevatten geen
persoonsgegevens, en ze op te halen is de taak van elke
zoekmachinecrawler.
Domein en identificatie: wat in het toegangslogboek ontbreekt
Het toegangslogboek van werkzeug schrijft noch de aangesproken host noch de identificatie van de aanroeper mee. Odoo krijgt beide vanzelfsprekend — zonder de host zou het bij meerdere websites niet eens de juiste kunnen kiezen. Achteraf nalezen kan het echter niet.
Web RBL legt beide per treffer vast. Dat beantwoordt twee vragen die anders niet te beantwoorden zijn: welke website een foutieve configuratie aanspreekt — en daarmee welke klant het domein toebehoort — en of een adres één pagina bezoekt of alle. Meerdere niet-samenhangende domeinen van hetzelfde adres zijn het kenmerk van de bulkactie, en ze verhogen de score.
Hoeveel de identificatie uitmaakt, toonde een analyse op een
van onze websites: meer dan zeventig procent van het totale verkeer
kwam daar van één enkele aanroeper, verdeeld over meer dan
honderd adressen. Zonder de identificatie had dat eruit gezien als een
gedistribueerde scraper. Het was GPTBot, de crawler van OpenAI
— die steeds opnieuw naar robots.txt vroeg en
zich volkomen correct gedroeg.
De beveiligingsaspecten in detail
1. De proxyherkenning — het gevaarlijkste punt van allemaal
Draait Odoo achter een reverse proxy en is proxy_mode
verkeerd ingesteld, dan ziet de module bij elk verzoek hetzelfde adres:
dat van de proxy. Een blokkade zou dan alle bezoekers tegelijk
buitensluiten.
Daarom controleert Web RBL vóór elke blokkade of de adresbepaling
betrouwbaar is. Het eist proxy_mode samen met
een doorstuur-header, weigert te werken als een
doorsturing zonder proxy_mode binnenkomt, en weigert dat
evenzo bij meer dan één tussenliggende proxy. In geval van twijfel wordt niet
geblokkeerd.
2. Eigen netwerken nooit
Privé-adresbereiken, loopback, link-local en CGNAT zijn vast uitgezonderd. Ze kunnen onder geen enkele omstandigheid op de lijst belanden, ook niet met de hand. Hetzelfde geldt voor externe lijsten: privé- en gereserveerde bereiken en absurd grote netwerken worden bij het inlezen verworpen.
3. Een eigen fout mag de website niet meenemen
De volledige controle draait in een beveiligingslaag die elke fout opvangt. Wat hier misgaat, wordt gelogd, en het verzoek loopt ongewijzigd verder. Een beveiligingsmodule die bij een eigen fout de website meeneemt, is erger dan helemaal geen. Alle query’s in het verzoekpad draaien bovendien zonder de browsertaal van de bezoeker en zonder sortering op vertaalde velden — een bezoeker met een niet-geïnstalleerde taal mag de controle niet laten mislukken.
4. Observeren vóór blokkeren
Na de installatie is het blokkeren van vermelde adressen bij gewone verzoeken uitgeschakeld. Sondes worden geweigerd en geboekt, al het andere loopt door. Zo kan men enkele dagen meelezen wie er werkelijk op de lijst belandt, voordat iemand wordt buitengesloten. Hetzelfde geldt voor gedragsherkenning, dreigingslijsten en landregels: eerst melden, blokkeren na beoordeling.
5. Smalle patronen in plaats van brede netten
Een ten onrechte herkende bezoeker is duurder dan een gemiste sonde.
Elk patroon draagt daarom zijn niveau, en dat is per patroon
aan te passen. Een bestandsextensie alleen volstaat zelden: bij
.php staan 14.012 echte sondes tegenover een handvol
oude links, bij .asp is de verhouding omgekeerd. Zulke
beslissingen moeten gemeten worden, niet geschat.
6. Een handmatige vrijgave blijft bestaan
Wie een adres vrijgeeft, had daar een reden voor. Een volgende treffer zet die beslissing niet stilzwijgend buiten werking.
7. De lijst is beschermd, maar geen geheim
Het eindpunt eist een token en antwoordt zonder geldig token
met 404, niet met 403 — het bestaan
van het adres wordt zo niet eens bevestigd. De vergelijking verloopt
in constante tijd. De lijst zelf bevat niets vertrouwelijks: ze
bestaat uit adressen die uit zichzelf bij ons hebben aangeklopt.
8. Geen geheimen in de boekhouding
Bij mislukte aanmeldingen wordt de geprobeerde gebruikersnaam vastgelegd, nooit het wachtwoord. Bij de databasebeheerder wordt uit de doorgegeven waarden helemaal niets gelezen: daar staat vooraan het hoofdwachtwoord, en een vermelding in een blokkeerlijst belandt in elke databaseback-up. De licentiesleutel voor GeoLite2 staat alleen in de systeemparameter en in geen enkele logregel.
9. Het lokaas verraadt niets bruikbaars
Optioneel beantwoordt Web RBL sondes met verzonnen inhoud die een unieke kanariewaarde bevat. Wie die waarde later opvraagt, heeft het valse antwoord gelezen en is daarop gaan handelen — een valse melding is daarbij uitgesloten. Het lokaas bevat geen bruikbare gegevens, geen echte paden en geen geldige toegangsgegevens. Deze functie wordt uitgeschakeld geleverd, want ze verandert het gedrag naar buiten toe zichtbaar.
Wat de module niet kan
Ze vervangt geen firewall en geen Web Application Firewall. Ze herkent bekende verkenningspatronen in paden, mislukte aanmeldingen en opvallend gedrag — geen aanvallen op formulieren, geen injectiepogingen in parameters.
Ze ziet bovendien alleen wat via HTTP terugkomt. Wat een aanvaller met buitgemaakte database- of mailboxtoegang doet, blijft onzichtbaar — en juist daarom zijn de kanariewaarden paden en geen toegangsgegevens.
En ze vervangt geen zorgvuldigheid: een module die
.env-sondes weigert, maakt een per ongeluk
uitgeleverd .env-bestand niet ongevaarlijk.
Beschikbaarheid
Web RBL is onder de AGPL-3 openbaar beschikbaar en draait bij ons in productie op vijf websites:
github.com/Alex0176/odoo-web-rbl
De module vereist Odoo 19 Community en heeft geen
afhankelijkheden behalve base en web. De
ticketkoppeling is optioneel en vereist geen specifiek
ticketsysteem; zonder zo’n systeem gebeurt er gewoon niets. Het
herkomstland vereist de gratis GeoLite2-database van MaxMind;
ontbreekt die, dan blijft het veld leeg en werkt al het andere
ongewijzigd.
Verder lezen: Hoe Web RBL past in een complete beveiligingsarchitectuur -- samen met firewall, tweefactorauthenticatie en rechten, inclusief stapsgewijze handleiding: Odoo 19-beveiligingsarchitectuur juist combineren.
Vragen, opmerkingen en foutrapporten nemen wij graag in ontvangst — het liefst als issue op GitHub.