Odoo-Sicherheitshärtung: Authentifizierung, Zugriffsrechte und Verschlüsselung
Unternehmens-ERP-Systeme sind hochwertige Ziele für Cyberangriffe. Eine Odoo-Instanz, die personenbezogene Daten von Kunden, Finanzunterlagen, Lieferantenverträge und Mitarbeiterdaten enthält, stellt eine erhebliche Angriffsfläche dar, die bewusste, mehrschichtige Sicherheitskontrollen erfordert.
Dieser Leitfaden deckt den gesamten Prozess der Sicherheitshärtung für Odoo 19 Enterprise ab: von der Authentifizierungsstärkung und der Gestaltung von Zugriffsrechten bis hin zur Netzwerkhärtung, Verschlüsselung, Audit-Protokollierung und Bereitschaft zur Reaktion auf Vorfälle.
Wichtige Erkenntnisse
– Standardmäßige Odoo-Konfigurationen sind aus Sicherheitsgründen nicht produktionsbereit
- Die Zwei-Faktor-Authentifizierung (2FA) sollte für alle Benutzer mit sensiblen Zugriffen obligatorisch sein
- Zugriffsrechte folgen dem Prinzip der geringsten Rechte – Benutzer erhalten nur das, was sie benötigen – Datensatzregeln bieten Sicherheit auf Zeilenebene, um die Datenisolation zu erzwingen – Die gesamte Kommunikation zwischen Diensten muss TLS verwenden; niemals HTTP in der Produktion
- Datenbankanmeldeinformationen müssen regelmäßig rotiert werden und dürfen niemals fest codiert werden
- Audit-Protokolle müssen manipulationssicher sein und für Compliance-Anforderungen aufbewahrt werden
- Sicherheitspatches sollten innerhalb von 48 Stunden nach Ankündigungen von Odoo SA angewendet werden
Authentifizierungshärtung
Passwortrichtlinie
Odoo 19 unterstützt konfigurierbare Passwortrichtlinien unter Einstellungen → Benutzer & Unternehmen → Passwort-Reset-Richtlinie.
Empfohlene Einstellungen:
- Mindestlänge: 12 Zeichen
- Erfordern Groß- und Kleinschreibung, Zahlen und Sonderzeichen
- Passwortablauf: 90 Tage
- Verhindern Sie die Wiederverwendung der letzten 12 Passwörter
- Kontosperrung nach 5 Fehlversuchen (15-minütige Sperrung)
# Custom password validator in a security module
from odoo import api, models
from odoo.exceptions import UserError
import re
class ResUsers(models.Model):
_inherit = 'res.users'
@api.constrains('password')
def _check_password_strength(self):
for user in self:
if user.password:
pwd = user.password
if len(pwd) < 12:
raise UserError("Password must be at least 12 characters.")
if not re.search(r'[A-Z]', pwd):
raise UserError("Password must contain an uppercase letter.")
if not re.search(r'[a-z]', pwd):
raise UserError("Password must contain a lowercase letter.")
if not re.search(r'\d', pwd):
raise UserError("Password must contain a number.")
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', pwd):
raise UserError("Password must contain a special character.")
Zwei-Faktor-Authentifizierung (2FA)
Aktivieren Sie 2FA unter Einstellungen → Berechtigungen → Zwei-Faktor-Authentifizierung.
Konfigurationsmöglichkeiten:
- Optional: Benutzer entscheiden, ob 2FA aktiviert werden soll
- Für bestimmte Gruppen erforderlich: Gilt für Administratoren und Buchhalter
- Für alle Benutzer erforderlich: Maximale Sicherheit
Für Unternehmensbereitstellungen ist 2FA erforderlich für:
- Administratorkonten (
base.group_system) – Finanzbenutzer (account.group_account_manager) - Personalmanager mit Zugriff auf die Gehaltsabrechnung
- Alle Benutzer mit API-Schlüsselzugriff
OAuth- und SSO-Integration
Für Organisationen mit bestehenden Identitätsanbietern konfigurieren Sie Odoo für die Verwendung von SAML 2.0 oder OAuth 2.0:
# In odoo.conf — configure OAuth
oauth_providers = [
{
'name': 'Your SSO Provider',
'client_id': 'odoo-client-id',
'auth_endpoint': 'https://sso.company.com/auth',
'validation_endpoint': 'https://sso.company.com/userinfo',
'scope': 'openid email profile',
}
]
Dies zentralisiert die Authentifizierung bei Ihrem Identitätsanbieter und ermöglicht Funktionen wie Single Sign-On, zentralisierte MFA und automatische Kontoaufhebung, wenn Mitarbeiter das Unternehmen verlassen.
API-Schlüsselsicherheit
# Restrict API key creation to administrators only
# In custom security module:
# ir.rule to prevent non-admin users from creating API keys
<record id="rule_api_key_admin_only" model="ir.rule">
<field name="name">API Keys: Admin Only</field>
<field name="model_id" ref="base.model_auth_api_key"/>
<field name="domain_force">[('create_uid', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
Erzwingen Sie eine Richtlinie: API-Schlüssel laufen nach 90 Tagen ab, sind an dedizierte Dienstkonten mit minimalen Berechtigungen gebunden und werden bei jeder vermuteten Kompromittierung rotiert.
Architektur der Zugriffsrechte
Design der Gruppenhierarchie
Die Zugriffskontrolle von Odoo basiert auf Gruppen. Entwerfen Sie eine Gruppenhierarchie, die Ihre Organisationsstruktur widerspiegelt:
base.group_user (Internal User)
├── sales.group_sale_salesman (Salesperson)
│ └── sales.group_sale_manager (Sales Manager)
├── account.group_account_user (Accounting User)
│ └── account.group_account_manager (Accounting Manager)
├── stock.group_stock_user (Inventory User)
│ └── stock.group_stock_manager (Inventory Manager)
└── base.group_system (Administrator)
Prinzip der geringsten Berechtigung: Jeder Benutzer sollte über den für die Ausführung seiner Aufgabe erforderlichen Mindestzugriff verfügen. Dadurch wird der Explosionsradius kompromittierter Konten begrenzt.
Zugriffskontrolllisten (ACL)
ACL-Einträge in ir.model.access definieren CRUD-Berechtigungen auf Modellebene:
id,name,model_id,group_id,perm_read,perm_write,perm_create,perm_unlink
# Salesperson: can read/write own orders, cannot delete
access_sale_order_salesman,sale.order.salesman,sale.model_sale_order,sales.group_sale_salesman,1,1,1,0
# Manager: full CRUD
access_sale_order_manager,sale.order.manager,sale.model_sale_order,sales.group_sale_manager,1,1,1,1
# Accounting user: read-only on sales orders
access_sale_order_accountant,sale.order.accountant,sale.model_sale_order,account.group_account_user,1,0,0,0
Datensatzregeln (Sicherheit auf Zeilenebene)
Datensatzregeln filtern, welche Datensätze ein Benutzer in einem Modell sehen kann:
<!-- Salesperson sees only their own opportunities -->
<record id="rule_crm_salesman" model="ir.rule">
<field name="name">CRM: Own Leads</field>
<field name="model_id" ref="crm.model_crm_lead"/>
<field name="domain_force">
['|', ('user_id', '=', user.id), ('user_id', '=', False)]
</field>
<field name="groups" eval="[(4, ref('sales.group_sale_salesman'))]"/>
</record>
<!-- Multi-company isolation: users see only their company's records -->
<record id="rule_sale_order_company" model="ir.rule">
<field name="name">Sale Order: Company</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="domain_force">
[('company_id', 'in', company_ids)]
</field>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
</record>
Leistungswarnung: Komplexe Datensatzregeln mit vielen search()- oder child_of-Operatoren können Listenansichten erheblich verlangsamen. Testen Sie alle Datensatzregeln anhand großer Datenmengen, bevor Sie sie in der Produktion bereitstellen.
Netzwerksicherheit
TLS/HTTPS-Durchsetzung
Führen Sie Odoo in der Produktion niemals über einfaches HTTP aus. Der gesamte Datenverkehr muss verschlüsselt sein.
Nginx TLS-Konfiguration:
server {
listen 80;
server_name your-odoo.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-odoo.com;
ssl_certificate /etc/ssl/certs/your-odoo.com.pem;
ssl_certificate_key /etc/ssl/private/your-odoo.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:
ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
# HSTS: 2 years, include subdomains
add_header Strict-Transport-Security
"max-age=63072000; includeSubDomains; preload" always;
# Security headers
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Permissions-Policy
"camera=(), microphone=(), geolocation=()" always;
}
Firewall-Konfiguration
# UFW firewall rules for Odoo server
ufw default deny incoming
ufw default allow outgoing
# Allow SSH from management IP only
ufw allow from 10.0.1.100 to any port 22
# Allow HTTPS from anywhere
ufw allow 443/tcp
# Allow HTTP (for Let's Encrypt renewal)
ufw allow 80/tcp
# Allow PostgreSQL only from Odoo server (if separate DB server)
ufw allow from 10.0.1.10 to any port 5432
# Block direct access to Odoo port (must go through Nginx)
ufw deny 8069/tcp
ufw deny 8072/tcp
ufw enable
Ratenbegrenzung
Konfigurieren Sie die Ratenbegrenzung in Nginx, um Brute-Force-Angriffe zu verhindern:
# Rate limiting zones
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=60r/m;
server {
# Apply rate limiting to login endpoint
location /web/login {
limit_req zone=login burst=3 nodelay;
limit_req_status 429;
proxy_pass http://odoo;
}
# Apply rate limiting to API
location /web/dataset/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://odoo;
}
}
Datenverschlüsselung
Verschlüsselung auf Datenbankebene
Für hochsensible Daten können Odoo-Felder im Ruhezustand verschlüsselt werden:
# Custom encrypted field using Fernet symmetric encryption
from cryptography.fernet import Fernet
from odoo import api, fields, models
import base64, os
class EncryptedField(models.Model):
_name = 'my.sensitive.model'
_fernet_key = os.environ.get('ODOO_FIELD_ENCRYPTION_KEY')
ssn_encrypted = fields.Char(string='SSN (Encrypted)', groups='hr.group_hr_user')
ssn_display = fields.Char(
string='SSN', compute='_compute_ssn_display',
inverse='_inverse_ssn_display'
)
def _get_fernet(self):
return Fernet(self._fernet_key.encode())
def _compute_ssn_display(self):
f = self._get_fernet()
for record in self:
if record.ssn_encrypted:
decrypted = f.decrypt(record.ssn_encrypted.encode()).decode()
record.ssn_display = f"***-**-{decrypted[-4:]}"
else:
record.ssn_display = False
def _inverse_ssn_display(self):
f = self._get_fernet()
for record in self:
if record.ssn_display:
encrypted = f.encrypt(record.ssn_display.encode()).decode()
record.ssn_encrypted = encrypted
Sicherheit der Umgebungsvariablen
Speichern Sie Geheimnisse niemals im Klartext in odoo.conf. Umgebungsvariablen verwenden:
# /etc/systemd/system/odoo.service
[Service]
Environment="ODOO_DB_PASSWORD=your_secure_password"
Environment="ODOO_ADMIN_PASSWD=your_master_password"
Environment="ODOO_FIELD_ENCRYPTION_KEY=your_fernet_key"
EnvironmentFile=/etc/odoo/secrets.env
# odoo.conf — reference env vars
[options]
db_password = ${ODOO_DB_PASSWORD}
admin_passwd = ${ODOO_ADMIN_PASSWD}
Audit-Protokollierung
Die integrierte Audit-Protokollierung von Odoo verfolgt alle Modelländerungen. Aktivieren Sie es für sensible Modelle:
# Enable audit logging via the Audit Trail module
# Or implement custom logging:
class AuditableMixin(models.AbstractModel):
_name = 'audit.mixin'
def write(self, vals):
# Log what changed before the write
for record in self:
old_vals = {f: record[f] for f in vals if f in record._fields}
self.env['audit.log'].create({
'model_name': self._name,
'record_id': record.id,
'user_id': self.env.uid,
'action': 'write',
'old_values': str(old_vals),
'new_values': str(vals),
'ip_address': self.env.context.get('remote_addr'),
})
return super().write(vals)
def unlink(self):
for record in self:
self.env['audit.log'].create({
'model_name': self._name,
'record_id': record.id,
'user_id': self.env.uid,
'action': 'unlink',
'old_values': str({f: record[f] for f in ['name', 'id']}),
})
return super().unlink()
Zu prüfende Compliance-kritische Modelle:
res.users(Benutzererstellung, Berechtigungsänderungen)account.move(Rechnungsänderungen)hr.payslip(Gehaltsabrechnungsänderungen)res.partner(Kunden-/Kreditoren-PII-Änderungen)ir.model.access,ir.rule(Berechtigungsänderungen)ir.config_parameter(Systemkonfigurationsänderungen)
Sicherheitspatch-Verwaltung
Abonnieren Sie Odoo-Sicherheitshinweise:
Odoo SA veröffentlicht Sicherheitshinweise unter https://github.com/odoo/odoo/security/advisories. Abonnieren Sie GitHub-Benachrichtigungen für dieses Repository.
Patch-Anwendungsprozess:
# Check current Odoo version
python3 odoo-bin --version
# Pull latest security patches (within a minor version)
cd /opt/odoo
git fetch origin
git log origin/19.0..HEAD --oneline # See what's changed
# Apply patches on staging first
git merge origin/19.0
python3 odoo-bin -d staging_db -u all --stop-after-init
# Test critical workflows on staging
# If all clear, apply to production during maintenance window
Ziel: Patch innerhalb von 48 Stunden nach einem kritischen oder hohen Schweregrad. Mittlerer Schweregrad: innerhalb einer Woche. Niedriger Schweregrad: nächstes geplantes Wartungsfenster.
Häufig gestellte Fragen
Wie überprüfe ich, wer einen Datensatz in Odoo gelöscht hat?
Odoo protokolliert Löschungen standardmäßig nicht. Installieren Sie das auditlog-Modul der Odoo Community Association (OCA) oder implementieren Sie eine benutzerdefinierte unlink()-Überschreibung in Ihren sensiblen Modellen. Das OCA-Auditlog-Modul protokolliert Erstellungs-, Schreib- und Verknüpfungsvorgänge mit einem auditlog.log-Modell mit Änderungsverfolgung auf Benutzer-, Zeitstempel- und Feldebene.
Kann ich den Odoo-Zugriff anhand der IP-Adresse einschränken?
Nicht nativ in Odoo. Implementieren Sie IP-Zulassungslisten auf Nginx- oder Firewall-Ebene. Für den administrativen Zugriff ist eine VPN-Verbindung erforderlich. Odoos ir.config_parameter unterstützt zwar eine web.base.url-Einschränkung, aber echte IP-basierte Zugriffskontrolle gehört in die Netzwerkschicht.
Was ist der Unterschied zwischen Zugriffsrechten (ACL) und Datensatzregeln?
Zugriffsrechte (ACL, gespeichert in ir.model.access) steuern, ob eine Benutzergruppe einen Datensatz eines Modells lesen, schreiben, erstellen oder löschen kann – dies ist die Steuerung auf Modellebene. Datensatzregeln filtern mithilfe von Domänenausdrücken, auf welche spezifischen Datensätze ein Benutzer innerhalb eines Modells zugreifen kann – dies ist eine Steuerung auf Zeilenebene. Beides funktioniert zusammen: Ein Benutzer benötigt eine ACL-Leseberechtigung UND muss den Domänenfilter der Datensatzregel passieren, um einen Datensatz anzuzeigen.
Wie soll ich mit dem Odoo-Master-Passwort (admin_passwd) umgehen?
Das admin_passwd in odoo.conf steuert den Zugriff auf die Datenbankverwaltungsschnittstelle unter /web/database/manager. In der Produktion: Legen Sie eine lange Zufallszeichenfolge (32+ Zeichen) fest, speichern Sie sie in einem Passwort-Manager, geben Sie sie niemals weiter und ziehen Sie in Betracht, den Datenbankmanager mit list_db = False in odoo.conf vollständig zu deaktivieren, wenn Sie die Datenbank über direkten PostgreSQL-Zugriff verwalten.
Soll ich Odoo als Root ausführen?
Niemals. Erstellen Sie einen dedizierten odoo-Systembenutzer ohne Shell-Zugriff und eingeschränkten Dateisystemberechtigungen. Der Odoo-Benutzer benötigt Lesezugriff auf die Odoo-Codebasis und Schreibzugriff nur auf die Dateispeicher- und Protokollverzeichnisse. Führen Sie den systemd-Dienst als dieser Benutzer aus. Das Ausführen als Root verstößt gegen das Prinzip der geringsten Rechte und maximiert den Schaden durch jede Schwachstelle bei der Codeausführung.
Nächste Schritte
Die Härtung der Sicherheit ist keine einmalige Aufgabe, sondern eine fortlaufende Praxis. Neue Schwachstellen treten auf, Benutzerzugriffsanforderungen ändern sich und Compliance-Frameworks entwickeln sich weiter. Eine sichere Odoo-Bereitstellung erfordert regelmäßige Sicherheitsüberprüfungen, Disziplin bei der Patch-Verwaltung und Prüfungen der Zugriffsrechte.
ECOSIRE bietet Odoo-Sicherheitshärtungsbewertungen, die Fehlkonfigurationen, übermäßige Berechtigungen, fehlende Kontrollen und Compliance-Lücken identifizieren. Unser Sicherheitsteam hat Erfahrung mit ISO 27001-, SOC 2- und DSGVO-Anforderungen in Odoo-Umgebungen.
Anfordern einer Odoo-Sicherheitsbewertung von ECOSIRE →
Wir überprüfen Ihre aktuelle Konfiguration anhand von Industriestandards und liefern einen priorisierten Behebungsplan mit Implementierungsunterstützung.
Geschrieben von
ECOSIRE Research and Development Team
Entwicklung von Enterprise-Digitalprodukten bei ECOSIRE. Einblicke in Odoo-Integrationen, E-Commerce-Automatisierung und KI-gestützte Geschäftslösungen.
Verwandte Artikel
Odoo Accounting vs QuickBooks: Detailed Comparison 2026
In-depth 2026 comparison of Odoo Accounting vs QuickBooks covering features, pricing, integrations, scalability, and which platform fits your business needs.
API Rate Limiting: Patterns and Best Practices
Master API rate limiting with token bucket, sliding window, and fixed counter patterns. Protect your backend with NestJS throttler, Redis, and real-world configuration examples.
Case Study: eCommerce Migration to Shopify with Odoo Backend
How a fashion retailer migrated from WooCommerce to Shopify and connected it to Odoo ERP, cutting order fulfillment time by 71% and growing revenue 43%.