Odoo er tilgængelig fra det åbne internet på vores fem websider, og det er ikke en undtagelse, men normaltilfældet: Den, der driver et tilbud, en shop eller et kundelogin, har en offentlig server. En enkelt sårbar adgangskode, en glemt konfigurationsfil eller en for generøs rettighed er nok til, at en offentlig server bliver en åben server.
Dette indlæg viser, hvordan du sikrer Odoo 19 rigtigt — ikke med en enkelt foranstaltning, men med flere lag, der supplerer hinanden: firewall og reverse proxy, vores open source-modul Web RBL, tofaktorgodkendelse, adgangskodepolitik og rettigheder — og hvilke angrebsforsøg hver af dem faktisk opfanger. Til sidst følger en trin-for-trin-vejledning, som enhver egen Odoo-installation kan følge efter.
Indhold i dette indlæg
- Forsvar i dybden: hvorfor en enkelt foranstaltning aldrig rækker
- Lag 1: firewall og reverse proxy
- Lag 2: Web RBL — broen til firewallen
- Lag 3: Sikring af selve Odoo (2FA, adgangskodepolitik, rettigheder)
- Lag 4: database og drift
- Loginvejen i sin helhed
- Angrebsscenarier og deres modværn
- Trin-for-trin-vejledning
- Ofte stillede spørgsmål
Forsvar i dybden: hvorfor en enkelt foranstaltning aldrig rækker
Hver enkelt sikkerhedsforanstaltning har et hul. En firewall ser ikke, hvad der sker i en Odoo-loginformular. En stærk adgangskode beskytter ikke, hvis den allerede er blevet stjålet andetsteds. En rettighedsstruktur hjælper ikke mod en angriber, der slet ikke har logget ind endnu. Princippet, der lukker disse huller, hedder forsvar i dybden (defense in depth): flere uafhængige lag, hvoraf hvert enkelt for sig kunne omgås — men alle sammen netop ikke.
Hos os er det fire lag, hvert med sin egen opgave:
- Firewall / reverse proxy — holder det åbenlyst ondsindede væk, før det overhovedet når serveren
- Web RBL — forbinder begge sider: Odoo lærer af sin egen applikationslog, hvad firewallen slet ikke kan se, og fører det tilbage til den
- Selve Odoo — tofaktorgodkendelse, adgangskodepolitik, rettigheder, sessionsstyring
- Database & drift — sikkerhedskopiering, adgangsbeskyttelse af administrationen, hemmeligheder uden for enhver log
De følgende afsnit gennemgår hvert lag for sig.
Lag 1: firewall og reverse proxy
Firewallen er den første instans, der ser en forespørgsel, og den eneste, der kan holde en angriber væk fra enhver tjeneste på serveren — ikke kun fra websiden, men også fra mailserveren, VPN-adgangen og den egen administrationsflade. Hvad der giver mening at aktivere på dette sted, afhænger af producenten, men byggeformerne er de samme hos OPNsense, pfSense, HAProxy, FortiGate, Sophos eller Check Point:
| Funktion | Hvad den hjælper imod |
|---|---|
| Aktuel TLS-version og begrænsede krypteringsmetoder | Aflytning og manipulation af forbindelsen; forældede metoder har i årevis været regnet for brudte eller svage |
| Reputations- og oprindelseslister (RBL) | Kendte angribernetværk, Tor-exitnoder, hele lande uden egne kunder — se nedenfor |
| Hastighedsbegrænsning pr. adresse | Afprøvning af adgangskoder og mappescannere, der stiller dusinvis af forespørgsler på få sekunder |
| Adskillelse af administration og datatrafik | Selve firewallens administrationsflade må ikke kunne nås via den samme adresse som den offentlige webside |
| IDS/IPS (angrebsgenkendelse/-forsvar) | Kendte angrebsmønstre på netværksniveau, uafhængigt af, hvilken applikation der kører bagved |
| Automatiske sikkerhedsopdateringer til selve firewallen | En ikke-patchet firewall er ikke længere en firewall, men et ekstra mål |
RBL-lister: standardvejen, hvorpå reputation leveres
RBL står for Real-time Blackhole List, et begreb fra mailverdenen: én adresse pr. linje, tilgængelig via HTTP, genindlæst jævnligt. Stort set enhver firewall kan indlæse en sådan liste og bygge regler ud fra den — OPNsense og pfSense som URL Table Alias, HAProxy som ACL-fil, FortiGate som External Block List, Palo Alto som External Dynamic List, Cisco, Sophos, Juniper og MikroTik med egne navne for det samme princip.
Netop her sætter vores eget modul ind — og netop her begynder det andet lag.
Lag 2: Web RBL — broen mellem applikation og firewall
En firewall ser pakker, ikke applikationslogik. Den ved ikke, at en forespørgsel efter /xmlrpc/2/common er et loginforsøg, at tyve forskellige stier på fjorten sekunder er en scanner, eller at en adresse netop har gættet en adgangskode med held. Alt det ved kun Odoo selv. Web RBL, vores eget open source-modul (AGPL-3), gør denne viden anvendelig — for Odoo selv og, leveret som RBL-liste, også for firewallen foran.
Trusselslister afstemmes løbende, hver med eget niveau.
Kort opsummeret, hvad der er beskrevet udførligt i det forrige indlæg:
- Mønstergenkendelse i stier:
.env-filer,.git-mapper, konfigurationsfiler, WordPress- og PHP-sonder, stitraversering, kommandoudførelse via nye AI-grænseflader - Loginforsvar, der tæller på tværs af genstarter — i modsætning til Odoos egen tæller, som lever i arbejdshukommelsen
- Score for hver adresse fra 0 til 100, med begrundelse i klartekst
- Fejlkonfigurationer (QNAP, Autodiscover, Synology) genkendes og bliver aldrig spærret, fordi en spærring ikke afhjælper defekten, men kun skjuler den
- Fremmede trusselslister som Spamhaus, FireHOL og Tor-exitnoder, afstemt løbende
- Positivliste for adresser, der aldrig må spærres
For dette indlæg er to egenskaber særligt vigtige, fordi de hænger direkte sammen med firewallen og med login.
En træg liste er en liste, man kan stole på
Positivlisten — adresser, der aldrig spærres, f.eks. egne lokationsforbindelser — ændrer sig som regel sjældent. Netop det er dens værdi, ikke dens mangel: Når en rolig liste knap bevæger sig over dage, falder enhver sjælden ændring straks i øjnene. Den daglige automatiske opdatering findes ikke, fordi meget ville ændre sig, men for at den sjældne ændring ikke skal efterføres i hånden — og netop det er det punkt, hvor man glemmer det. En af vores egne fejlkonfigurationer i den forgangne måned faldt netop sådan i øjnene: ikke ved mange hændelser, men ved den ene, som ingen kendte, indtil en kundes QNAP-web-API fejlagtigt blev spærret. Siden da står QNAP på listen over fejlkonfigurationer, der aldrig spærres, men kun indberettes.
Login er det sted, en firewall ikke ser
En firewall kan spærre en adresse. Den kan ikke vide, om et login lykkedes, og slet ikke, om det kom fra en adresse, der kort forinden endnu ledte efter adgangsdata. Det kan Web RBL: En score fra en indstillelig tærskelværdi forbyder login helt, og et vellykket login fra en påfaldende adresse bliver indberettet — det er bindeleddet til det næste lag.
Lag 3: Sikring af selve Odoo
Tofaktorgodkendelse: en anden hemmelighed, der ikke kan genbruges
Det største problem ved adgangskoder er ikke deres kvalitet, men deres genbrug. En adgangskode, der er stjålet hos en anden tjeneste, virker hos os på samme måde, så længe den er den samme. Tofaktorgodkendelse (2FA, også kaldet TOTP) sætter en anden hemmelighed op imod det: en sekscifret kode, der ændrer sig hvert tredivte sekund og beregnes ud fra en hemmelighed, som kun ens egen smartphone kender. En stjålet adgangskode alene rækker dermed ikke længere.
Odoo 19 Community har det indbygget — som installerbart modul Two-Factor Authentication (TOTP), suppleret med en e-mail-reservemulighed. Hver bruger sætter det op for sig selv, via QR-kode, med enhver gængs authenticator-app:
Opsætningen: scan QR-koden, bekræft den sekscifrede kode én gang, færdig.
Det hjælper dog kun dem, der selv sætter det op — og erfaringen viser, at det uden tvang forbliver mindretallet. Odoo kender derfor en håndhævelsespolitik: enten kun for medarbejdere (interne brugere) eller for alle, portalbrugere inklusive. Uden en opsat anden hemmelighed kommer ingen længere forbi loginformularen uden i det mindste at bekræfte via en e-mail-kode.
Adgangskodepolitik: en mindstelængde er ikke en selvfølge
Uden tillægsmodul forlader Odoo Community sig ikke på nogen mindstelængde for adgangskoder — en bruger kan vælge en adgangskode på tre tegn, hvis ingen forhindrer det. Det egne Password Policy-modul lukker netop dette hul: en mindstelængde, der håndhæves på serversiden og ikke kun foreslås i browseren. Den, der vil have mere — en tvungen udløbstid, en historik mod genbrug — har brug for et OCA- eller tredjepartsmodul; det er bevidst holdt slankt i Community-versionen.
Rettigheder: kun den, der har brug for det, får adgang
Odoo adskiller fra start tre niveauer: portalbrugere (kun den egen kunde- eller leverandørportal), interne brugere (backend, med rettigheder pr. applikation) og administratorer (ubegrænset adgang inklusive tekniske indstillinger). Den hyppigste fejl er ikke en for svag adgangskode, men en for generøst tildelt administratorrolle: Den, der kun skal oprette fakturaer, har ikke brug for adgang til systemindstillingerne.
To grundsætninger bærer det meste af læsset:
API-nøgle i stedet for adgangskode: hver ekstern tilslutning (regnskabssoftware, tidsregistrering, egne scripts) får sin egen nøgle, der til enhver tid kan tilbagekaldes, aldrig brugerens adgangskode.
Begge dele kan kontrolleres i den samme visning, hvor tofaktorgodkendelsen også sættes op:
Én oversigt, fire håndtag: adgangskode, anden faktor, API-nøgler, loggede enheder.
Sessioner og enheder: hvem er logget ind lige nu
Den samme visning viser også, fra hvilke enheder en konto lige nu er logget ind — og gør det muligt at logge en enkelt eller alle ud på én gang. Efter en tabt bærbar eller mistanke om en kompromitteret adgangskode er det det hurtigste virksomme skridt: Sessionen ophører øjeblikkeligt, uanset om adgangskoden allerede er ændret.
Lag 4: database og drift
Det fjerde lag er det mindst synlige og samtidig det mest utilgivelige, fordi en fejl her kan gøre alt, der tidligere er bygget op, til intet.
/web/database/manager en flade, hvormed databaser kan oprettes, sikkerhedskopieres, gendannes og slettes — beskyttet kun af en enkelt masteradgangskode. Denne flade skal udelukkende være tilgængelig internt eller slås helt fra.
- Regelmæssige, afprøvede sikkerhedskopier, gemt adskilt fra selve serveren. En sikkerhedskopi, der aldrig er blevet gendannet, er en formodning, ikke en sikkerhedskopi.
- Hemmeligheder hører ikke hjemme i nogen logfil. Adgangskoder, API-nøgler, licensdata — den, der skriver egne udvidelser, bør behandle dem som selve masteradgangskoden: skriv dem ingen steder, heller ikke »bare til debugging«.
- Hold moduler opdaterede, også og især tredjepartsmoduler. Frie tillægsmoduler (OCA og andre) kommer naturligt bagefter nye Odoo-versioner; før hver installation er det værd at se på, hvilke afhængigheder der automatisk kommer med.
Loginvejen i sin helhed
De fire lag virker ikke efter hinanden i adskilte rum, men på den samme forespørgsel, trin for trin. Det bliver tydeligst med et login som eksempel:
Fem steder, hvor en ondsindet forespørgsel kan ende, før den når det egentlige mål — og kun ét enkelt sted, hvor en berettiget bruger består dem alle.
Angrebsscenarier og deres modværn
Den følgende oversigt knytter reelle angrebsmønstre til de lag, der faktisk stopper dem. Flere af dem er ikke teori, men egne iagttagelser fra sytten dages ægte trafik på vores fem websider.
| Angrebsscenarie | Hvordan det forløber | Hvad der stopper det |
|---|---|---|
| Afprøvning af adgangskoder | Et script prøver hundredvis af kombinationer mod loginformularen eller XML-RPC | Firewallens hastighedsbegrænsning, Web RBL-tæller på tværs af genstarter, spærring efter ti forsøg, øjeblikkelig spærring ved ignoreret ventemeddelelse |
| Genbrugte adgangsdata stjålet andetsteds | Angriberen kender allerede brugernavn og adgangskode — fra en anden, hacket tjeneste | Tofaktorgodkendelse stopper loginet trods korrekt adgangskode; Web RBL indberetter desuden et vellykket login fra en påfaldende adresse |
| Søgning efter glemte hemmeligheder | Automatiserede forespørgsler efter .env, .git, cloud-adgangsnøgler — hos os 57.721 forespørgsler på sytten dage alene efter .env |
Web RBL spærrer ved det første hit; firewallen får derefter adressen med som RBL-post for alle andre tjenester |
| Mappe- og stiscannere | Dusinvis af opdigtede stier på få sekunder, på jagt efter glemte applikationer | Adfærdsgenkendelse: mange fejlsider, næsten ingen hits, på kort tid — uafhængigt af, om stien rammer et kendt mønster |
| Fejlkonfigureret eget apparat | En synkroniseringsklient eller et e-mailprogram peger ved en fejl på den forkerte adresse og banker på hvert minut | Genkendelse som fejlkonfiguration i stedet for som angreb, ticket i stedet for spærring — spærringen ville ikke afhjælpe defekten, kun trække den ud |
| Automatiseret dataindsamling af obligatoriske oplysninger | En indsamler henter impressum-sider under fremmede stavemåder, ofte som forberedelse til en bølge af advarsler | Den kanoniske sti forbliver altid tilgængelig (juridisk nødvendigt), fremmede stavemåder genkendes og indberettes eller spærres |
| Mistet eller stjålet enhed | En logget bærbar eller mobiltelefon falder i forkerte hænder | Sessionsoversigt med øjeblikkelig udlogning af alle enheder, uafhængigt af adgangskoden |
| For vidt fastsat intern rettighed | En brugerkonto med flere rettigheder end nødvendigt bliver kompromitteret eller misbrugt | Mindst nødvendige rettighed pr. applikation begrænser fra starten skaden til det, som kontoen virkelig har brug for |
| Misbrug af en ekstern grænseflade | En stjålet API-nøgle eller et kompromitteret tredjepartssystem tilgår via XML-RPC/JSON-RPC | Egne, tilbagekaldelige API-nøgler i stedet for brugerens adgangskode; Web RBL overvåger også mislykkede RPC-logins |
| Fejlvurderet søgemaskine-crawler | En legitim crawler skaber så meget trafik, at den ser ud som en distribueret angriber — på en af vores sider var det over halvfjerds procent af al trafik, forårsaget af GPTBot | Positivliste med de offentliggjorte adresseintervaller for kendte søgemaskiner forhindrer en fejlspærring, som ville tage den egen side ud af indekseringen |
| Forældet tredjepartsmodul med kendt sårbarhed | En sikkerhedssårbarhed i et frit tillægsmodul bliver offentlig, opdateringen kommer først uger senere | Før hver installation kontrolleres, hvad der automatisk kommer med; opdateringer først på en testinstans, ikke på åbent hjerte |
| Åben databaseadministration | Administrationsfladen kan nås via det åbne internet; en gættet eller svag masteradgangskode er nok til at slette eller kopiere databaser | Fladen eksponeres aldrig offentligt, masteradgangskoden forbliver lang, tilfældig og noteret ingen steder |
Trin for trin: sikring af din egen Odoo-installation
Den følgende rækkefølge er den, vi selv ville gå frem i — fra den største virkning til den fineste indstilling.
1. Gør tofaktorgodkendelse obligatorisk
- Hvis det ikke allerede er installeret: åbn Apps, søg efter »Two-Factor Authentication« og installér det (ved flere websider anbefales desuden »Two-Factor Authentication by Mail« som reservemulighed).
- Åbn Indstillinger → Generelle indstillinger → Rettigheder.
- Aktivér »Gør tofaktorgodkendelse obligatorisk«.
- Vælg politik: »Kun medarbejdere« for interne brugere, »Alle brugere«, hvis også portalbrugere (kunder med adgang) skal medtages.
- Gem. Fra det næste loginforsøg kræver Odoo af hver bruger uden opsat anden hemmelighed som minimum e-mail-koden, indtil vedkommende har sat authenticator-appen op.
2. Fastsæt en mindstelængde for adgangskoder
- Åbn Apps, søg efter »Password Policy« og installér det.
- Åbn Indstillinger → Generelle indstillinger → Rettigheder.
- Sæt »Adgangskodens mindstelængde« — tolv tegn er en fornuftig startværdi.
- Gem. Reglen gælder fra nu af for hver ny eller ændret adgangskodetildeling, ikke med tilbagevirkende kraft for eksisterende adgangskoder.
3. Gennemgå rettigheder
- Åbn Indstillinger → Brugere & virksomheder → Brugere.
- Åbn hver bruger enkeltvis og kontrollér fanen med adgangsrettighederne pr. applikation: Har denne person virkelig brug for »Manager« eller »Administrator«, eller rækker »Bruger«?
- Kontrollér især: Hvem har adgang til selve »Indstillinger«? Det bør være en meget lille gruppe.
- Opret for hver ekstern tilslutning (regnskab, egne scripts, tidsregistrering) i fanen »Kontosikkerhed« hos den pågældende tekniske bruger en egen API-nøgle i stedet for at give brugerens adgangskode videre.
4. Installér Web RBL og observér, før der slås til
- Læg modulet fra github.com/Alex0176/odoo-web-rbl i addon-stien og installér det.
- Observér i nogle dage: Menuen Web RBL → Analyse viser, hvilke mønstre der faktisk slår til.
- Først derefter slås
web_rbl.sperren_aktivtil (Indstillinger → Teknisk → Systemparametre) — fra nu af afvises genkendte sonder faktisk. - Tilslut spærrelisten under den i modulet angivne, med token beskyttede adresse i firewallen som RBL-liste (ved OPNsense/pfSense som URL Table Alias, ved HAProxy som ACL-fil).
5. Sikr selve firewallen
- Gør firewallens administrationsflade udelukkende tilgængelig fra det interne netværk, aldrig via den samme offentlige adresse som websiden.
- Aktivér automatiske sikkerhedsopdateringer til firewall-softwaren, hvis producenten tilbyder det.
- Kontrollér TLS-konfigurationen: kun aktuelle protokolversioner, deaktivér forældede krypteringsmetoder.
- Hvis muligt: tilslut en kendt reputationsliste (f.eks. Spamhaus DROP) direkte på firewallen — uafhængigt af Web RBL, for firewallen ser dermed også trafik til tjenester, som Odoo aldrig når.
6. Luk databaseadministrationen
- Kontrollér, om
/web/database/managerkan nås udefra — hvis ja, sætlist_db = Falsei Odoo-konfigurationen eller spær stien på firewall-niveau. - Sæt databaseadministrationens masteradgangskode lang og tilfældig, og noter den ikke noget sted, som nogen anden kan læse.
7. Kontrollér sikkerhedskopien, opsæt den ikke blot
- Opsæt en automatisk, regelmæssig sikkerhedskopi, gemt adskilt fra Odoo-serveren.
- Gendan den mindst én gang faktisk og kontrollér, om gendannelsen fungerer — en ukontrolleret sikkerhedskopi er en formodning.
Ingen af disse trin erstatter et af de andre. Den, der kun gennemfører ét af dem, har forstærket én dør og ladet alle andre stå åbne — den, der gennemfører alle syv, har et forsvar, der holder, selv når et enkelt lag svigter.
Hvad denne arkitektur ikke erstatter
Ingen af de beskrevne foranstaltninger gør omhyggelighed overflødig. Et modul, der afviser .env-sonder, gør en ved en fejl offentliggjort .env-fil ikke ufarlig. Tofaktorgodkendelse beskytter ikke mod en bruger, der læser sin kode op for en opringer i telefonen. Og en firewall erstatter ikke en beslutning om, hvem der faktisk har brug for hvilken rettighed. Sikkerhedsarkitektur skaber de betingelser, under hvilke en enkelt fejl ikke straks bliver til en hændelse — den fritager ingen for omhyggelighed.
Ofte stillede spørgsmål
Er en stærk adgangskode nok til at sikre Odoo 19?
Nej. En adgangskode kan stjæles andetsteds, helt uafhængigt af dens kvalitet, og virker så hos enhver tjeneste, der accepterer den samme adgangskode. Først kombinationen med tofaktorgodkendelse, en firewall foran og en fornuftig rettighedsstruktur giver en sikring, der holder, også efter en stjålet adgangskode.
Hvordan aktiverer jeg tofaktorgodkendelse i Odoo 19?
Installér modulet »Two-Factor Authentication (TOTP)« via Apps-administrationen, aktivér derefter håndhævelsen under Indstillinger → Generelle indstillinger → Rettigheder og vælg mellem »Kun medarbejdere« og »Alle brugere«. Hver bruger sætter derefter sin egen anden faktor op via QR-kode.
Hvad er en RBL-liste, og hvorfor har Odoo brug for en?
RBL (Real-time Blackhole List) er en adresseliste, der kan hentes via HTTP, og som stort set enhver firewall kan indlæse. Odoo leverer selv ikke en sådan liste — vores modul Web RBL lukker dette hul ved at genkende angrebstrafik i den egen applikationslog og give den tilbage som RBL-liste til den forudgående firewall.
Er Odoo 19 Community uden tillægsmoduler tilstrækkeligt sikret?
Ikke fuldstændigt. Uden modulet Password Policy findes der ingen mindstelængde for adgangskoder, uden Two-Factor Authentication ingen anden faktor, og uden et modul som Web RBL genkender Odoo hverken sonderingsforsøg eller gentagne loginforsøg på tværs af en genstart. Alle fire kan eftermonteres gratis.
Tilgængelighed
Web RBL er offentligt tilgængeligt under AGPL-3 og kører hos os produktivt på fem websider:
github.com/Alex0176/odoo-web-rbl
Den fuldstændige funktionsbeskrivelse med alle mønstre, scoren og trusselslisterne står i det forrige indlæg: Web RBL – spærreliste for angrebstrafik på de egne websider.
Spørgsmål, bemærkninger og fejlrapporter modtager vi gerne — helst som issue på GitHub.