Webserver ohne eine Web Application Firewall sind verwundbar, egal wie sicher der Anwendungscode wirkt. SQL-Injection, Cross-Site-Scripting und Path-Traversal-Attacken treffen täglich Tausende Produktionssysteme, weil der HTTP-Datenstrom ungefiltert bei der Anwendung ankommt. ModSecurity 3, kombiniert mit dem OWASP Core Rule Set und Nginx, liefert eine ausgereifte Open-Source-WAF, die du in unter 60 Minuten auf Ubuntu 22.04 oder 24.04 produktionsreif einrichten kannst. Diese Anleitung zeigt alle 12 Schritte vom ersten apt-get-Aufruf bis zum aktiven Blocking-Modus.
Was ist eine Web Application Firewall?
Eine Web Application Firewall (WAF) analysiert HTTP- und HTTPS-Anfragen auf Anwendungsschicht (OSI-Schicht 7), bevor sie die eigentliche Webanwendung erreichen. Klassische Netzwerk-Firewalls arbeiten auf Schicht 3 und 4 und kennen keinen Unterschied zwischen einem legitimen POST-Request und einem SQL-Injection-Versuch, solange Quell-IP und Zielport erlaubt sind. Eine WAF versteht den Inhalt der Anfrage und kann gefährliche Muster erkennen und blockieren.
Die häufigsten Angriffsvektoren, gegen die eine WAF schützt, sind im OWASP Top 10 dokumentiert: SQL-Injection (A03), Cross-Site-Scripting/XSS (A03), Broken Access Control (A01) und Server-Side Request Forgery (A10). ModSecurity, das seit 2002 entwickelt wird und heute von der OWASP Foundation betreut wird, ist die am weitesten verbreitete Open-Source-WAF-Engine und läuft als Modul vor Apache, Nginx und IIS.
Der entscheidende Vorteil einer Reverse-Proxy-WAF vor Nginx: Alle Anfragen, ob HTTP oder HTTPS, passieren die WAF-Engine, bevor sie an Backend-Dienste wie Node.js, PHP-FPM oder einen Java-Appserver weitergereicht werden. Nach der TLS-Terminierung durch Nginx sieht ModSecurity den entschlüsselten Klartext und kann auch verschlüsselte Angriffe abfangen.
Für Betreiber von Webdiensten in Deutschland ist eine WAF mittlerweile keine optionale Maßnahme mehr. Die NIS2-Richtlinie und der Cyber Resilience Act (CRA) erwarten von betroffenen Organisationen nachweisbare technische Schutzmaßnahmen auf Anwendungsebene. ModSecurity mit OWASP CRS erfüllt diese Anforderungen direkt.
ModSecurity 3 im Überblick
ModSecurity 3 (intern als libmodsecurity bekannt) ist ein vollständiger Neuaufbau gegenüber der Version 2 und bringt drei wesentliche Verbesserungen mit sich: eine saubere C++-Bibliothek mit öffentlichem API, unabhängige Konnektoren für verschiedene Webserver (Nginx, Apache, IIS) und einen aktiv gepflegten GitHub-Monorepo unter github.com/owasp-modsecurity/ModSecurity. Auf der offiziellen Projektseite wird ModSecurity als “Swiss Army Knife” der Web Application Firewalls beschrieben.
Für Ubuntu 22.04 LTS ist ModSecurity v3.0.13 aus den Paketquellen verfügbar, liegt aber hinter dem Entwicklungsstand des GitHub-Repositorys zurück. Für Ubuntu 24.04 und für Produktionsumgebungen, bei denen exakte ABI-Kompatibilität mit dem installierten Nginx-Binary gefragt ist, empfiehlt sich die Kompilierung aus dem Quellcode. Der Mehraufwand gegenüber apt-get install beträgt etwa 10 bis 15 Minuten.
Im April 2025 wurde CVE-2025-47947 für ModSecurity in der Ubuntu-Sicherheitsdatenbank dokumentiert. Diese Schwachstelle betrifft ausschließlich die ältere 2.9.x-Serie (Apache-Modul). Installationen mit ModSecurity 3 sind von diesem CVE nicht betroffen. Dennoch gilt: Jede produktive WAF-Installation sollte regelmäßig auf neue Sicherheitsupdates geprüft werden.
Ein praktischer Überblick über die Architektur: Der Nginx-Prozess empfängt eine Anfrage, reicht sie an das dynamisch geladene Modul ngx_http_modsecurity_module.so weiter, welches die Anfrage an die libmodsecurity-Bibliothek übergibt. Die Bibliothek prüft die Anfrage gegen alle geladenen Regeln (OWASP CRS plus eigene Regeln), gibt dann eine Entscheidung zurück (erlaubt, blockiert oder geloggt), und Nginx handelt entsprechend.
OWASP Core Rule Set: Die Grundlage jeder WAF
ModSecurity ohne Regeln ist wie ein Türsteher ohne Gästeliste: technisch präsent, aber praktisch wirkungslos. Das OWASP Core Rule Set (CRS) liefert über 200 vorkonfigurierte Erkennungsregeln, die auf jahrelanger Angreiferforschung basieren und regelmäßig aktualisiert werden. Die Regeln sind thematisch nach Angriffskategorie gruppiert und jeweils mit einer eindeutigen numerischen Regel-ID versehen. Das CRS-Projekt wird unter coreruleset.org und auf GitHub aktiv weiterentwickelt.
Ein zentrales Konzept des CRS ist das Paranoia-Level: Level 1 aktiviert nur sehr sichere Regeln mit niedrigem False-Positive-Risiko. Level 4 aktiviert alle Regeln inklusive solcher, die legitimen Traffic treffen könnten. Für eine neue Installation ist Level 1 oder 2 der richtige Ausgangspunkt.
| Regel-ID-Bereich | Schutzbereich | Beispiel-Angriff |
|---|---|---|
| 900000–909999 | CRS-Initialisierung und Grundkonfiguration | Paranoia-Level-Einstellung |
| 910000–919999 | IP-Reputation und Scanner-Erkennung | Bekannte Angriffs-IPs, Port-Scanner |
| 920000–929999 | Protokoll-Erzwingung | Fehlende Host-Header, ungültige HTTP-Methoden |
| 930000–939999 | Local File Inclusion (LFI) | ../../../etc/passwd |
| 931000–931999 | Remote File Inclusion (RFI) | Externe URL in Dateiparametern |
| 932000–932999 | Remote Code Execution (RCE) | Shell-Injektionen, Systemaufrufe |
| 933000–933999 | PHP-Injection | eval(), base64_decode() in Parametern |
| 941000–941999 | Cross-Site-Scripting (XSS) | <script>alert(1)</script> |
| 942000–942999 | SQL-Injection | 1' OR '1'='1, UNION-Angriffe |
| 943000–943999 | Session-Fixation | Session-ID-Manipulation |
| 944000–944999 | Java-Injection | Log4Shell-ähnliche Payloads |
Voraussetzungen
Das Tutorial setzt einen Server mit Ubuntu 22.04 LTS oder 24.04 LTS voraus. Alle Befehle werden als Root oder mit sudo-Rechten ausgeführt. Für Ubuntu 22.04 können einige Schritte durch Paket-Installation abgekürzt werden, wenn libmodsecurity3 aus den Ubuntu-Paketquellen ausreichend aktuell ist. Ubuntu 24.04 erfordert aktuell die Kompilierung aus dem Quellcode, da die Paketversion hinter dem GitHub-Stand zurückbleibt und mit aktuellen Nginx-Versionen nicht kompatibel ist.
| Komponente | Mindestversion | Empfohlen | Funktion |
|---|---|---|---|
| Ubuntu | 22.04 LTS | 24.04 LTS | Betriebssystem |
| Nginx | 1.24.0 | 1.26.x stable | Webserver / Reverse Proxy |
| libmodsecurity3 | 3.0.8 | 3.0.13 oder neuer | WAF-Engine |
| ModSecurity-nginx Connector | aktueller master | aktueller master | Nginx-Modul |
| OWASP CRS | 3.3.x | 4.x (neueste Version) | Regelwerk |
| Git | 2.x | beliebig | Repository-Klonen |
| GCC / G++ | Version 11 | Version 13 | Kompilierung |
| RAM | 1 GB | 2 GB oder mehr | Kompilierung und Betrieb |
Stelle vor dem Start sicher, dass du die exakte Nginx-Version kennst. Die Ausgabe von nginx -v zeigt die Versionsnummer, gegen die der Konnektor kompiliert werden muss. Eine Versionsdiskrepanz führt zu einem ABI-Inkompatibilitätsfehler beim Start.
Schritt 1: Build-Abhängigkeiten installieren
Der erste Schritt installiert alle Bibliotheken und Build-Tools, die für die Kompilierung von libmodsecurity3 und dem Nginx-Konnektor benötigt werden. Der Vorgang dauert auf einem typischen VPS mit 2 CPU-Kernen etwa 2 Minuten.
sudo apt-get update
sudo apt-get install -y \
git build-essential automake autoconf libtool pkg-config \
libcurl4-openssl-dev libpcre2-dev libpcre3-dev libxml2-dev \
libyajl-dev libgeoip-dev liblmdb-dev libmaxminddb-dev \
libssl-dev libxml2-utils libgd-dev doxygen flex bison \
ca-certificates wget curl zlib1g-dev
Falls libpcre2-dev auf Ubuntu 22.04 nicht gefunden wird, reicht libpcre3-dev allein. ModSecurity 3 unterstützt beide PCRE-Versionen, bevorzugt aber PCRE2 wegen besserer Performance bei komplexen Mustern. Das Paket libmaxminddb-dev ist für das spätere GeoIP-Blocking erforderlich und sollte direkt mitinstalliert werden.
Schritt 2: libmodsecurity3 aus dem Quellcode kompilieren
Die Kompilierung von libmodsecurity3 dauert auf einem 2-Core-VPS typischerweise 5 bis 10 Minuten. Das Flag -j"$(nproc)" nutzt alle verfügbaren CPU-Kerne parallel und halbiert die Kompilierungszeit gegenüber einem einzelnen Kern.
cd /usr/local/src
sudo git clone --depth 1 -b v3/master --single-branch \
https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
sudo git submodule init
sudo git submodule update
sudo ./build.sh
sudo ./configure
sudo make -j"$(nproc)"
sudo make install
sudo ldconfig
Der Schritt git submodule update ist entscheidend: Er lädt abhängige Bibliotheken wie ssdeep und einen LZMA-Decoder nach. Ohne diesen Schritt bricht ./configure mit Fehlern über fehlende Header-Dateien ab. Nach erfolgreichem make install liegt die fertige Bibliothek unter /usr/local/lib/libmodsecurity.so.3. Der abschließende ldconfig-Aufruf registriert sie im dynamischen Bibliothekspfad des Systems.
Prüfe den Erfolg mit:
ldconfig -p | grep modsecurity
# Erwartete Ausgabe:
# libmodsecurity.so.3 (libc6,x86-64) => /usr/local/lib/libmodsecurity.so.3
Schritt 3: Nginx-Quellcode herunterladen
Der ModSecurity-Nginx-Konnektor ist ein dynamisches Nginx-Modul. Er muss zwingend gegen dieselbe Nginx-Version kompiliert werden, die auf dem System läuft. Selbst ein Minor-Version-Unterschied (1.24.0 vs. 1.24.1) kann zu Startfehlern führen.
# Installierte Nginx-Version ermitteln
nginx -v
# Beispielausgabe: nginx version: nginx/1.24.0
# Passenden Nginx-Quellcode herunterladen
cd /usr/local/src
sudo wget http://nginx.org/download/nginx-1.24.0.tar.gz
sudo tar -xzf nginx-1.24.0.tar.gz
Falls Nginx noch nicht installiert ist, installiere es zuerst über die offiziellen Nginx-Paketquellen. Weitere Details zur Nginx-Konfiguration als Reverse Proxy findest du in unserem Nginx Reverse Proxy Tutorial und zur automatischen HTTPS-Einrichtung in der Anleitung zu Let’s Encrypt Zertifikaten.
Schritt 4: ModSecurity-Nginx-Konnektor kompilieren
Jetzt wird der eigentliche Nginx-Konnektor als dynamisches Modul kompiliert. Das Resultat ist eine .so-Datei (Shared Object), die Nginx beim Start lädt und die Verbindung zur libmodsecurity-Bibliothek herstellt.
cd /usr/local/src
sudo git clone https://github.com/SpiderLabs/ModSecurity-nginx.git
cd nginx-1.24.0
sudo ./configure --with-compat --add-dynamic-module=../ModSecurity-nginx
sudo make modules
# Kompiliertes Modul in Nginx-Verzeichnis kopieren
sudo cp objs/ngx_http_modsecurity_module.so /usr/lib/nginx/modules/
sudo chmod 0644 /usr/lib/nginx/modules/ngx_http_modsecurity_module.so
Das Flag --with-compat ist entscheidend: Es aktiviert den ABI-Kompatibilitätsmodus, sodass das Modul mit einem bereits installierten Nginx-Binary zusammenarbeitet, ohne Nginx selbst neu kompilieren zu müssen. Ohne dieses Flag schlägt das Laden des Moduls zur Laufzeit mit einem ABI-Fehler fehl, obwohl die Kompilierung selbst erfolgreich war.
Schritt 5: Nginx-Modul laden und testen
Das kompilierte Modul muss Nginx beim Start bekannt gemacht werden. Füge die folgende Zeile ganz oben in /etc/nginx/nginx.conf ein, noch vor dem events-Block.
# /etc/nginx/nginx.conf (Anfang der Datei)
load_module modules/ngx_http_modsecurity_module.so;
events {
worker_connections 1024;
}
http {
# ... bestehende Konfiguration bleibt unverändert
}
Konfiguration prüfen und Nginx neu laden:
sudo nginx -t
# Erwartete Ausgabe:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo systemctl reload nginx
Wenn nginx -t einen Fehler über ein nicht binär-kompatibles Modul meldet, wurde der Konnektor gegen eine falsche Nginx-Version kompiliert. Prüfe nginx -v erneut und wiederhole Schritt 3 und 4 mit der korrekten Version.
Schritt 6: ModSecurity-Konfigurationsverzeichnis einrichten
ModSecurity erwartet seine Konfiguration in einem eigenen Verzeichnis. Erstelle die Verzeichnisstruktur und kopiere die mitgelieferte Beispielkonfiguration als Ausgangspunkt.
sudo mkdir -p /etc/nginx/modsec
# Empfohlene Basiskonfiguration kopieren
sudo cp /usr/local/src/ModSecurity/modsecurity.conf-recommended \
/etc/nginx/modsec/modsecurity.conf
# Unicode-Mapping-Datei für Zeichenkodierungs-Erkennung
sudo cp /usr/local/src/ModSecurity/unicode.mapping \
/etc/nginx/modsec/unicode.mapping
Die Datei unicode.mapping hilft ModSecurity, Unicode-Kodierungen wie %u0027 (einfaches Anführungszeichen) in SQL-Injektionsversuchen zu erkennen. Ohne diese Datei können bestimmte Umgehungstechniken über Unicode-Kodierungen die WAF passieren.
Schritt 7: modsecurity.conf konfigurieren
Die Datei /etc/nginx/modsec/modsecurity.conf steuert das Grundverhalten der Web Application Firewall. Bearbeite sie mit einem Editor und passe die folgenden Schlüsselparameter an.
# WAF-Modus: DetectionOnly = nur loggen, On = blockieren
# Immer mit DetectionOnly starten und erst nach Tuning auf On wechseln!
SecRuleEngine DetectionOnly
# HTTP-Request-Body inspizieren (notwendig für POST-Angriffe)
SecRequestBodyAccess On
# Response-Body-Inspektion ist ressourcenintensiv, zunächst deaktivieren
SecResponseBodyAccess Off
# Maximale Request-Body-Größe (13 MB)
SecRequestBodyLimit 13107200
SecRequestBodyNoFilesLimit 131072
SecRequestBodyLimitAction Reject
# Audit-Log: Nur relevante Ereignisse loggen
SecAuditEngine RelevantOnly
SecAuditLog /var/log/nginx/modsec_audit.log
SecAuditLogParts ABIJDEFHZ
SecAuditLogFormat JSON
# PCRE-Limits als Schutz vor Regular-Expression-DoS (ReDoS)
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000
# Temporäre Verzeichnisse für Request-Body-Daten
SecTmpDir /tmp/
SecDataDir /tmp/
Der Parameter SecAuditLogFormat JSON erzeugt maschinenlesbare Logs, die sich direkt mit jq, Elasticsearch oder Grafana Loki verarbeiten lassen. Das klassische Format ist zwar kompakter, erschwert aber die Automatisierung und Auswertung erheblich.
Erstelle nun die zentrale Include-Datei, die Nginx als Einstiegspunkt für die WAF-Konfiguration verwendet:
sudo bash -c 'cat > /etc/nginx/modsec/main.conf << "EOF"
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/crs-setup.conf
Include /etc/nginx/modsec/rules/*.conf
EOF'
Schritt 8: OWASP Core Rule Set installieren
Das OWASP CRS ist das Herzstück jeder ModSecurity-basierten Web Application Firewall. Die Installation direkt aus dem GitHub-Repository ermöglicht spätere Updates per git pull.
cd /etc/nginx/modsec
# OWASP CRS klonen
sudo git clone https://github.com/coreruleset/coreruleset.git rules
# Beispielkonfiguration als aktive Konfiguration verwenden
sudo cp /etc/nginx/modsec/rules/crs-setup.conf.example \
/etc/nginx/modsec/crs-setup.conf
# Anzahl der installierten Regelfiles prüfen
ls /etc/nginx/modsec/rules/rules/*.conf | wc -l
# Ausgabe: sollte mehr als 25 Dateien zeigen
Das Paranoia-Level in crs-setup.conf anpassen. Die Datei enthält die entsprechende Zeile bereits auskommentiert:
# In /etc/nginx/modsec/crs-setup.conf: Zeile suchen und anpassen
# Paranoia-Level 1 = Standard (empfohlen für neuen Installationen)
# Paranoia-Level 2 = empfohlen für Produktionssysteme nach Tuning
SecAction \
"id:900000,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=1"
Das OWASP CRS enthält zusätzlich optionale Plugin-Regeln für spezifische Anwendungen (WordPress, Drupal, NextCloud) im Unterverzeichnis plugins/. Für eine Standard-Installation sind diese nicht erforderlich.
Schritt 9: Nginx-Serverkonfiguration mit WAF aktivieren
Jetzt wird ModSecurity in der Nginx-Serverkonfiguration aktiviert. Bearbeite deine bestehende Site-Konfiguration in /etc/nginx/sites-available/ oder erstelle eine neue.
# /etc/nginx/sites-available/meine-app
server {
listen 80;
server_name example.de www.example.de;
# Web Application Firewall aktivieren
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
access_log /var/log/nginx/meine-app-access.log;
error_log /var/log/nginx/meine-app-error.log;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 443 ssl;
server_name example.de www.example.de;
ssl_certificate /etc/letsencrypt/live/example.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.de/privkey.pem;
# WAF auch fuer HTTPS aktivieren
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
Konfiguration aktivieren und Nginx neu laden:
sudo ln -s /etc/nginx/sites-available/meine-app \
/etc/nginx/sites-enabled/meine-app
sudo nginx -t
sudo systemctl reload nginx
Schritt 10: WAF im Erkennungsmodus testen
Bevor der Blocking-Modus aktiviert wird, muss die WAF im DetectionOnly-Modus gründlich getestet werden. Sende zunächst einen normalen Request, um zu prüfen, ob der Nginx-Stack insgesamt funktioniert.
# Normaler Request: sollte mit 200 oder 404 antworten
curl -i http://localhost/
# SQL-Injection-Test (Regel 942100 sollte ansprechen)
curl -i "http://localhost/?id=1%20OR%201=1"
# XSS-Test (Regel 941100 sollte ansprechen)
curl -i "http://localhost/?q=%3Cscript%3Ealert(1)%3C%2Fscript%3E"
# Path-Traversal-Test (Regel 930100 sollte ansprechen)
curl -i "http://localhost/?file=../../../etc/passwd"
# Shell-Injection-Test (Regel 932100 sollte ansprechen)
curl -i "http://localhost/?cmd=;cat%20/etc/passwd"
Im DetectionOnly-Modus antwortet der Server weiterhin mit 200 oder 404, aber das Audit-Log enthält die Treffer. Das Log auslesen:
# Log in Echtzeit verfolgen (mit jq fuer lesbares JSON)
sudo tail -f /var/log/nginx/modsec_audit.log | jq \
'.transaction | {uri: .request.uri, rules: [.messages[].details.ruleId]}'
# Oder ohne jq: rohe Ausgabe der letzten Eintraege
sudo tail -20 /var/log/nginx/modsec_audit.log
Erwartete JSON-Ausgabe im Audit-Log beim SQL-Injection-Test:
{
"transaction": {
"time": "17/Jun/2026:14:23:01 +0000",
"id": "abc123def456",
"request": {
"uri": "/?id=1 OR 1=1",
"method": "GET",
"http_version": 1.1
},
"messages": [
{
"message": "SQL Injection Attack Detected via libinjection",
"details": {
"ruleId": "942100",
"severity": "CRITICAL",
"tags": ["OWASP_CRS", "attack-sqli"]
}
}
],
"response": {
"http_code": 200
}
}
}
Schritt 11: False Positives identifizieren und beheben
Das Tuning von False Positives ist der zeitaufwendigste, aber wichtigste Schritt vor dem Wechsel in den Blocking-Modus. Typische Quellen von False Positives in modernen Webanwendungen:
- REST-APIs mit JSON-Body: Felder, die SQL-ähnliche Schlüsselwörter enthalten (
{"type": "select"}) - JWT-Token in Query-Strings: Base64-kodierte Inhalte triggern bestimmte Kodierungs-Regeln
- GraphQL-Abfragen: Verschachtelte Queries werden oft als Angriffsmuster erkannt
- Rich-Text-Editoren: HTML-Inhalte in Parametern (Regel 941100)
- File-Upload-Endpunkte: Base64-kodierte Dateiinhalte im Body
- Suchfelder: Nutzer suchen oft nach technischen Begriffen wie "SELECT" oder "WHERE"
Gezielten Ausschluss für einzelne Endpunkte erstellen. Lege dafür eine eigene Ausnahmedatei an:
# /etc/nginx/modsec/exclusions.conf
# SQLi-Regel (942100) nur fuer API-Upload-Endpunkt deaktivieren
SecRule REQUEST_URI "@beginsWith /api/v1/upload" \
"id:1000001,\
phase:1,\
pass,\
nolog,\
ctl:ruleRemoveById=942100"
# XSS-Regel (941100) fuer Rich-Text-Editor-Endpunkt
SecRule REQUEST_URI "@beginsWith /admin/editor" \
"id:1000002,\
phase:1,\
pass,\
nolog,\
ctl:ruleRemoveById=941100"
# Bestimmten Parameter global von der SQLi-Pruefung ausschliessen
SecRuleUpdateTargetById 942100 "!ARGS:content"
Die Ausnahmedatei in main.conf einbinden:
# /etc/nginx/modsec/main.conf (aktualisiert)
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/crs-setup.conf
Include /etc/nginx/modsec/rules/*.conf
Include /etc/nginx/modsec/exclusions.conf
Welche Regeln am häufigsten ansprechen, lässt sich schnell aus dem Audit-Log extrahieren:
sudo grep -o '"ruleId":"[0-9]*"' /var/log/nginx/modsec_audit.log | \
sort | uniq -c | sort -rn | head -20
Schritt 12: WAF auf Blocking-Modus schalten
Wenn das Audit-Log nach einer Testphase von mindestens 24 bis 48 Stunden keine unerwarteten False Positives mehr zeigt, kann die Web Application Firewall in den aktiven Blocking-Modus versetzt werden. Eine einzige Zeile in modsecurity.conf reicht dafür aus.
# Aenderung in /etc/nginx/modsec/modsecurity.conf
# ALT:
SecRuleEngine DetectionOnly
# NEU:
SecRuleEngine On
Alternativ mit sed ohne Editor:
sudo sed -i \
's/SecRuleEngine DetectionOnly/SecRuleEngine On/' \
/etc/nginx/modsec/modsecurity.conf
sudo nginx -t && sudo systemctl reload nginx
Jetzt blockiert die WAF erkannte Angriffe mit HTTP 403. Teste den Blocking-Modus sofort nach dem Reload:
curl -i "http://localhost/?id=1%20OR%201=1"
# HTTP/1.1 403 Forbidden
curl -i "http://localhost/?q=%3Cscript%3Ealert(1)%3C%2Fscript%3E"
# HTTP/1.1 403 Forbidden
# Normaler Request muss weiterhin funktionieren
curl -i "http://localhost/"
# HTTP/1.1 200 OK (oder 404, je nach Konfiguration)
Die 403-Fehlerseite lässt sich in Nginx mit einem eigenen HTML-Template anpassen, um Nutzern statt der Standard-Nginx-Seite eine hilfreiche Meldung anzuzeigen.
Häufige Probleme und Fehlerbehebung
ModSecurity ist eine ausgereifte Lösung, aber die Einrichtung enthält mehrere Stellen, an denen typische Fehler auftreten. Die folgenden 9 Probleme werden in fast jeder ModSecurity-Installation mindestens einmal angetroffen.
1. ABI-Mismatch beim Laden des Moduls
Fehlermeldung: nginx: [emerg] module "ngx_http_modsecurity_module.so" is not binary compatible
Ursache: Der Konnektor wurde gegen eine andere Nginx-Version kompiliert als die, die auf dem System läuft. Das passiert, wenn Nginx nachträglich aktualisiert wird, ohne den Konnektor neu zu bauen.
Lösung: Prüfe mit nginx -v die exakte laufende Version, lade den passenden Quellcode und wiederhole Schritt 3 und 4.
2. modsecurity.conf nicht gefunden
Fehlermeldung: open() "/etc/nginx/modsec/modsecurity.conf" failed (2: No such file or directory)
Lösung: Die Quelldatei modsecurity.conf-recommended wurde nicht kopiert. Prüfe mit ls /etc/nginx/modsec/, ob die Datei vorhanden ist, und wiederhole den Kopierbefehl aus Schritt 6.
3. CRS-Regeln werden nicht geladen
Symptom: Der SQL-Injection-Test aus Schritt 10 erzeugt keinen Audit-Log-Eintrag.
Diagnose und Lösung:
# Pruefe, ob Regelfiles vorhanden sind
ls /etc/nginx/modsec/rules/rules/*.conf | wc -l
# Erwartet: mehr als 25 Dateien
# Pruefe, ob crs-setup.conf korrekt eingebunden ist
cat /etc/nginx/modsec/main.conf
Häufige Ursache: git clone legte das Verzeichnis rules/rules/ an (Doppelpfad), aber main.conf referenziert rules/*.conf. Prüfe die exakte Verzeichnisstruktur und passe die Include-Pfade entsprechend an.
4. Nginx startet nach Konfigurationsänderung nicht
Diagnose:
sudo nginx -t 2>&1
sudo journalctl -u nginx --since "5 minutes ago"
Nginx gibt bei Syntaxfehlern in ModSecurity-Konfigurationsdateien genaue Fehlermeldungen mit Dateiname und Zeilennummer aus. Häufige Ursachen: fehlende Anführungszeichen in Regel-Strings oder ein inkomplettes git clone der CRS-Regeln.
5. Audit-Log wächst unkontrolliert
Ursache: SecAuditEngine All loggt jede einzelne Anfrage. Bei einem vielbesuchten Server kann das Gigabytes pro Tag erzeugen.
Lösung: Setze SecAuditEngine RelevantOnly und konfiguriere Log-Rotation:
# /etc/logrotate.d/modsecurity
/var/log/nginx/modsec_audit.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
postrotate
systemctl reload nginx
endscript
}
6. Performance-Einbruch bei File-Uploads
Ursache: ModSecurity versucht, den vollständigen Upload-Body zu inspizieren. Bei Bild- oder Video-Uploads führt das zu deutlichen Latenzen.
Lösung: Upload-Endpunkte gezielt von der Body-Inspektion ausschließen:
SecRule REQUEST_URI "@beginsWith /upload" \
"id:1000010,phase:1,pass,nolog,ctl:requestBodyAccess=Off"
7. Submodule-Fehler beim Kompilieren
Fehlermeldung während make: fatal error: ssdeep.h: No such file or directory
Ursache: git submodule update wurde übersprungen oder schlug wegen eines temporären Netzwerkfehlers fehl.
Lösung:
cd /usr/local/src/ModSecurity
sudo git submodule update --init --recursive
8. 403-Fehler bei legitimen API-Aufrufen nach Blocking-Aktivierung
Vorgehen: Wechsle temporär zurück zu DetectionOnly, reproduziere den 403-auslösenden Request und prüfe das Audit-Log auf die auslösende Regel-ID. Erstelle dann eine gezielte Ausnahme für diesen Endpunkt oder Parameter in exclusions.conf.
# Haeutig ausloesende Regeln finden
sudo grep -o '"ruleId":"[0-9]*"' /var/log/nginx/modsec_audit.log | \
sort | uniq -c | sort -rn | head -10
9. ldconfig findet libmodsecurity nicht
Fehlermeldung: error while loading shared libraries: libmodsecurity.so.3: cannot open shared object file
Lösung:
echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/modsecurity.conf
sudo ldconfig
ldconfig -p | grep modsecurity
Fortgeschrittene Konfiguration
Eigene Regeln schreiben
Neben dem CRS können anwendungsspezifische Regeln erstellt werden. Regel-IDs im Bereich 1000000 bis 1099999 sind für lokale Anpassungen reserviert und werden vom CRS nicht überschrieben.
# Bekannte Vulnerability-Scanner blockieren
SecRule REQUEST_HEADERS:User-Agent "@contains Nikto" \
"id:1000100,\
phase:1,\
deny,\
status:403,\
log,\
msg:'Vulnerability scanner blocked: Nikto'"
SecRule REQUEST_HEADERS:User-Agent "@contains sqlmap" \
"id:1000101,\
phase:1,\
deny,\
status:403,\
log,\
msg:'SQL injection tool blocked: sqlmap'"
OWASP CRS automatisch aktualisieren
Da das CRS aktiv weiterentwickelt wird und regelmäßig neue Angriffspattern aufnimmt, sollte es automatisch aktualisiert werden. Ein wöchentlicher Cronjob ist für die meisten Produktionsumgebungen ausreichend:
# /etc/cron.weekly/update-crs
#!/bin/bash
set -e
cd /etc/nginx/modsec/rules
git pull --ff-only
nginx -t && systemctl reload nginx
echo "CRS aktualisiert: $(git log -1 --pretty='%h %s')" | \
logger -t modsecurity-update
chmod +x /etc/cron.weekly/update-crs
Docker-Setup: ModSecurity 3 + Nginx als Container
Für containerisierte Umgebungen liefert das offizielle owasp/modsecurity-crs-Image eine fertige Kombination aus ModSecurity 3, Nginx und OWASP CRS, die vollständig über Umgebungsvariablen konfiguriert werden kann. Das spart den kompletten Kompilierungsaufwand der Schritte 1 bis 5.
# docker-compose.yml
version: "3.9"
services:
waf:
image: owasp/modsecurity-crs:nginx-alpine
ports:
- "80:80"
- "443:443"
environment:
- PARANOIA=1
- BACKEND=http://app:3000
- SERVER_NAME=example.de
- MODSEC_RULE_ENGINE=On
- BLOCKING_PARANOIA=2
volumes:
- ./custom-rules:/etc/modsecurity.d/custom
depends_on:
- app
app:
image: node:20-alpine
command: node server.js
volumes:
- ./app:/app
working_dir: /app
Container starten und Blocking-Modus testen:
docker compose up -d
# Angriff testen
curl -i "http://localhost/?id=1%20OR%201=1"
# Erwartete Antwort: HTTP/1.1 403 Forbidden
# WAF-Logs anzeigen
docker compose logs -f waf | grep ModSecurity
Performance-Tuning
ModSecurity kostet Rechenzeit, weil jede Anfrage gegen alle aktiven Regeln geprüft wird. Der tatsächliche Overhead hängt von der Anzahl aktiver Regeln, der Request-Körpergröße und dem gewählten Paranoia-Level ab. Die folgenden Maßnahmen reduzieren die Latenz ohne nennenswerte Einbußen beim Schutz.
| Optimierung | Geschätzte Einsparung | Schutzverlust |
|---|---|---|
| Response-Body-Inspektion deaktivieren | bis 30 % | Keiner bei typischen APIs |
| Paranoia-Level auf 1 belassen | 10 bis 20 % | Gering (weniger spekulative Regeln) |
| Statische Assets von WAF ausschließen | 5 bis 15 % | Keiner (CSS/JS/Bilder enthalten keine Nutzerdaten) |
| Nginx Worker-Prozesse an CPU-Kerne anpassen | Variabel | Keiner |
PCRE JIT kompilieren (--with-pcre-jit) | bis 20 % | Keiner |
Statische Assets von der WAF-Inspektion ausschließen:
location ~* \.(css|js|png|jpg|jpeg|gif|ico|woff2|woff|svg|webp)$ {
modsecurity off;
expires 30d;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
WAF-Logs professionell auswerten
Das Audit-Log ist das primäre Diagnosewerkzeug jeder WAF-Installation. Im JSON-Format enthält jeder Eintrag eine vollständige Beschreibung der verdächtigen Anfrage, der ausgelösten Regeln und der getroffenen Maßnahme. Das Verstehen des Log-Formats ist Voraussetzung für effektives Tuning und schnelle Incident-Response.
Ein vollständiger JSON-Audit-Log-Eintrag hat folgende Hauptfelder:
{
"transaction": {
"time": "17/Jun/2026:15:45:12 +0000",
"id": "Ymlqcpq0yAkAAFk9AAAAB",
"request": {
"uri": "/login?user=admin'--",
"method": "POST",
"http_version": 1.1,
"headers": {
"host": "example.de",
"user-agent": "Mozilla/5.0",
"content-type": "application/x-www-form-urlencoded"
}
},
"messages": [
{
"message": "SQL Injection Attack Detected via libinjection",
"details": {
"match": "Matched Data: s&e found within ARGS_GET:user: admin'--",
"ruleId": "942100",
"file": "REQUEST-942-APPLICATION-ATTACK-SQLI.conf",
"lineNumber": "4",
"data": "Matched Data: s&e found within ARGS_GET:user: admin'--",
"severity": "CRITICAL",
"ver": "OWASP_CRS/4.0.0",
"tags": ["language-multi", "platform-multi", "attack-sqli", "OWASP_CRS", "capec/1000/152/248/66"],
"maturity": "0",
"accuracy": "0"
}
}
],
"producer": {
"modsecurity": "ModSecurity v3/3.0.13",
"connector": "ModSecurity-nginx v1.0.3",
"secrules_engine": "Enabled"
},
"response": {
"http_code": 403,
"headers": {}
}
}
}
Die wichtigsten Felder im Überblick:
- transaction.id: Eindeutige ID pro Anfrage. Kann mit dem Nginx-
access.logkorreliert werden, wenn du die Variable$request_idin deinem Log-Format verwendest. - messages[].details.ruleId: Die ID der ausgelösten CRS-Regel. Direkte Verbindung zur Regel-Datei in
/etc/nginx/modsec/rules/rules/. - messages[].details.match: Zeigt genau, welcher Teil der Anfrage das Muster ausgelöst hat. Unverzichtbar für False-Positive-Diagnose.
- producer.secrules_engine: Zeigt den aktuellen Modus (Enabled = Blocking, DetectionOnly = Logging-Only).
Nützliche Shell-Befehle für die Log-Auswertung:
# Die 10 am haeufigsten angegriffenen URIs
sudo cat /var/log/nginx/modsec_audit.log | \
python3 -c "
import sys, json
for line in sys.stdin:
try:
d = json.loads(line)
t = d.get('transaction', {})
print(t.get('request', {}).get('uri', ''))
except: pass
" | sort | uniq -c | sort -rn | head -10
# Top-10 ausloesende Regel-IDs
sudo grep -o '"ruleId":"[^"]*"' /var/log/nginx/modsec_audit.log | \
sort | uniq -c | sort -rn | head -10
# Angriffsversuche der letzten Stunde zaehlen
sudo awk -v date="$(date -u +'%d/%b/%Y:%H')" \
'$0 ~ date {print}' /var/log/nginx/modsec_audit.log | wc -l
Wer die WAF-Telemetrie in eine bestehende Monitoring-Infrastruktur integrieren möchte, findet im OWASP-Ökosystem fertige Dashboards für den ELK-Stack (Elasticsearch, Logstash, Kibana). Das JSON-Format des Audit-Logs erlaubt direktes Ingest ohne Logstash-Parsing-Konfiguration.
Geo-Blocking und IP-Reputation
Wenn Angriffe konsistent aus bestimmten Ländern oder bekannten Angriffs-IP-Bereichen kommen, kann Geo-Blocking direkt in ModSecurity implementiert werden. Das ist effizienter als Geo-Blocking auf Nginx-Ebene, weil die Entscheidung innerhalb des WAF-Regelwerks getroffen und protokolliert wird.
Voraussetzung ist die GeoIP2-Datenbank von MaxMind (die kostenlose GeoLite2-Variante reicht für die meisten Anwendungsfälle). Nach der Registrierung auf maxmind.com ist der Download der GeoLite2-Country.mmdb-Datei kostenlos.
# MaxMind GeoLite2-Datenbank installieren
sudo apt-get install -y mmdb-bin
sudo mkdir -p /usr/share/GeoIP
# Manueller Download (Lizenzschluessel von maxmind.com erforderlich)
sudo wget -O /usr/share/GeoIP/GeoLite2-Country.mmdb \
"https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=DEIN_KEY&suffix=tar.gz"
# ModSecurity-Konfiguration fuer GeoIP
sudo bash -c 'cat >> /etc/nginx/modsec/modsecurity.conf << "EOF"
# GeoIP2-Datenbank laden
SecGeoLookupDB /usr/share/GeoIP/GeoLite2-Country.mmdb
EOF'
Geo-Blocking-Regel in der Ausnahmedatei oder einer eigenen Konfiguration aktivieren:
# Anfragen aus bestimmten Laendern zugelassen (Whitelist-Ansatz)
# Nur Deutschland, Oesterreich, Schweiz und EU erlaubt
SecRule REMOTE_ADDR "@geoLookup" \
"chain,\
id:1000300,\
phase:1,\
deny,\
status:403,\
log,\
msg:'Geo-Block: Unbekanntes Land'"
SecRule GEO:COUNTRY_CODE "!@within DE,AT,CH,FR,NL,BE,IT,ES,PL,SE,NO,DK,FI,PT,IE"
Der Whitelist-Ansatz (alle erlauben außer bestimmten Ländern) ist für die meisten europäischen Dienste sinnvoller als ein Blacklist-Ansatz, weil er False Positives bei Nutzern, die per VPN aus anderen Regionen zugreifen, sichtbar macht, ohne den Dienst für legitime Nutzer unzugänglich zu machen.
IP-Reputation über CRS-Regeln nutzen: Das CRS enthält in der Regelgruppe 910000 bereits IP-Reputationsprüfungen gegen bekannte Angriffs-IPs. Diese sind standardmäßig aktiv und nutzen keine externe API, sondern statische Listen, die mit dem CRS-Update aktualisiert werden.
WAF-Schutzwirkung verifizieren: CRS-Testsuite
Das CRS-Projekt enthält eine eigene Testsuite, die mit dem Tool go-ftw (Framework for Testing WAFs) gegen eine laufende WAF-Instanz ausgeführt wird. Die Testsuite prüft, ob jede einzelne Regel korrekt anspringt und ob keine Regeln durch Konfigurationsfehler oder Ausnahmen unbeabsichtigt deaktiviert wurden.
# go-ftw herunterladen (neueste Version von GitHub Releases)
ARCH=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
wget https://github.com/coreruleset/go-ftw/releases/latest/download/go-ftw_linux_${ARCH}.tar.gz
tar -xzf go-ftw_linux_${ARCH}.tar.gz
sudo mv ftw /usr/local/bin/go-ftw
go-ftw --version
# Konfigurationsdatei erstellen
cat > .ftw.yaml << "EOF"
testoverride:
input:
dest_addr: "127.0.0.1"
port: 80
protocol: "http"
EOF
# Alle CRS-Tests ausfuehren
cd /etc/nginx/modsec/rules
go-ftw run --dir tests/regression/scenarios/ --output=github
# Nur SQLi-Tests ausfuehren
go-ftw run --dir tests/regression/scenarios/ \
--include "942*" \
--output=github
Beispielausgabe der Testsuite:
Running go-ftw v1.x.x
...
[PASS] Test 942100-1: SQL Injection Attack (sqli_libinjection)
[PASS] Test 941100-1: XSS Attack (xss)
[PASS] Test 930100-1: Path Traversal Attack (/../)
[PASS] Test 932100-1: Remote Command Execution: Unix Shell Code Found
[FAIL] Test 9420XX-3: false positive fuer angepasste API-Route
Run: 500, Passed: 497, Failed: 3, Skipped: 0
Fehlgeschlagene Tests weisen entweder auf legitime False-Positive-Ausnahmen hin, die du definiert hast, oder auf einen Konfigurationsfehler. Die Testsuite ist besonders nach CRS-Updates oder Änderungen an den eigenen Ausnahmeregeln wertvoll, um unbeabsichtigte Auswirkungen auf den Schutz zu erkennen.
WAF und Defense-in-Depth: Weitere Sicherheitsschichten
Eine Web Application Firewall ist ein wichtiger Baustein, aber kein Allheilmittel. Das Schichten-Prinzip der Defense-in-Depth legt fest, dass jede Sicherheitsmaßnahme eine eigene Schutzebene bildet, sodass Angreifer mehrere Barrieren überwinden müssen. Kombiniert mit den folgenden Maßnahmen entsteht ein robustes Schutzkonzept, das auch den Anforderungen von NIS2 und dem Cyber Resilience Act gerecht wird.
- Nginx als Reverse Proxy mit HTTPS: TLS 1.3, HTTP/2, HSTS-Header und sichere Cipher Suites
- Let's Encrypt für automatische Zertifikate: Kostenfreie TLS-Zertifikate mit automatischer Erneuerung alle 90 Tage
- Fail2ban auf SSH und Nginx-Ebene: IP-basierter Brute-Force-Schutz, der IP-Adressen nach wiederholten Fehlversuchen blockt
- HTTP Security Headers: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options
- Rate Limiting in Nginx:
limit_req_zonefür API-Endpunkte schützt vor Brute-Force-Angriffen auf Anwendungsebene - Regelmäßige Schwachstellen-Scans: Werkzeuge wie OpenVAS oder Nikto identifizieren serverseitige Konfigurationsfehler, die eine WAF nicht abdeckt
Ein gut eingerichteter Nginx-Reverse-Proxy mit HTTPS und ModSecurity WAF bildet das Fundament jeder professionellen Web-Infrastruktur. Die WAF blockiert bekannte Angriffsmuster auf Anwendungsebene, während HTTPS die Vertraulichkeit und Integrität der Übertragung sicherstellt. Beide Maßnahmen zusammen decken die in der OWASP Top 10 beschriebenen Hauptrisiken für Webanwendungen weitgehend ab und erfüllen gleichzeitig technische Anforderungen, die von Datenschutzbehörden und Branchenstandards wie ISO 27001, BSI IT-Grundschutz und der NIS2-Richtlinie gefordert werden. Für eine vollständige Compliance sind zusätzlich Maßnahmen wie regelmäßige Penetrationstests, Patch-Management und Zugangskontrolle erforderlich, die über den Scope dieses Tutorials hinausgehen.
Details zu Nginx Reverse Proxy mit HTTPS findest du in unserem Nginx-Reverse-Proxy-Tutorial, zur Zertifikatsverwaltung im Let's Encrypt Tutorial und zum SSH-Schutz im Fail2ban-Tutorial. Den rechtlichen Rahmen für Web-Sicherheitsmaßnahmen in Deutschland erläutert unser NIS2-Artikel.
Alerting und automatische Reaktion auf Angriffe
Eine WAF im Blocking-Modus schützt passiv, indem sie Angriffe blockiert. Für eine proaktive Sicherheitsstrategie ist es sinnvoll, bei gehäuften Angriffsversuchen automatisch alarmiert zu werden und gegebenenfalls automatisch zu reagieren, etwa durch temporäres IP-Blocking über Fail2ban.
Fail2ban kann so konfiguriert werden, dass es das ModSecurity-Audit-Log überwacht und IP-Adressen, die innerhalb eines kurzen Zeitfensters mehr als eine bestimmte Anzahl von WAF-Treffern erzeugen, temporär auf Netzwerkebene sperrt. Das ergänzt die WAF-Blockierung auf Anwendungsebene um eine tiefere Verteidigungsebene.
# /etc/fail2ban/filter.d/modsecurity.conf
[Definition]
failregex = ^\{"transaction":\{"time":"[^"]+","id":"[^"]+","client_ip":""
ignoreregex =
# /etc/fail2ban/jail.d/modsecurity.conf
[modsecurity]
enabled = true
port = http,https
filter = modsecurity
logpath = /var/log/nginx/modsec_audit.log
maxretry = 5
findtime = 60
bantime = 3600
action = iptables-multiport[name=modsec, port="http,https", protocol=tcp]
Mit dieser Konfiguration wird eine IP-Adresse für 1 Stunde gesperrt, sobald sie innerhalb von 60 Sekunden 5 oder mehr WAF-Treffer erzeugt. Die Kombination aus ModSecurity (Anwendungsschicht) und Fail2ban (Netzwerkschicht) ist besonders effektiv gegen automatisierte Angriffs-Scanner und Brute-Force-Werkzeuge wie sqlmap, die typischerweise Hunderte von Anfragen pro Minute senden. Eine detaillierte Anleitung zur Fail2ban-Konfiguration findest du in unserem Fail2ban-Tutorial.
Für E-Mail-Benachrichtigungen bei ungewöhnlich hoher WAF-Aktivität kann ein einfaches Monitoring-Skript per Cronjob alle 15 Minuten das Audit-Log auf Spitzenwerte prüfen:
#!/bin/bash
# /etc/cron.d/modsec-alert (alle 15 Minuten)
THRESHOLD=50
ALERT_EMAIL="[email protected]"
LOG="/var/log/nginx/modsec_audit.log"
COUNT=$(awk -v ts="$(date -u -d '15 minutes ago' +'%d/%b/%Y:%H:%M')" \
'$0 > ts' "$LOG" 2>/dev/null | wc -l)
if [ "$COUNT" -gt "$THRESHOLD" ]; then
echo "WAF-Alarm: $COUNT Treffer in den letzten 15 Minuten" | \
mail -s "[WAF-Alert] Erhoehte Angriffsaktivitaet auf $(hostname)" \
"$ALERT_EMAIL"
fi
Wer eine vollständige SIEM-Integration anstrebt, kann das ModSecurity-JSON-Log direkt in Wazuh, OpenSearch oder Splunk einspeisen. Diese Plattformen bieten fertige Dashboards für WAF-Telemetrie und ermöglichen Korrelation mit anderen Sicherheitsereignissen wie SSH-Login-Fehlern oder DNS-Anomalien.
Weiterführende Artikel
Related Coverage
- Nginx Reverse Proxy: HTTPS in 12 Schritten einrichten [2026]
- Let's Encrypt: SSL-Zertifikat in 12 Schritten einrichten [2026]
- Fail2ban einrichten: SSH-Schutz in 12 Schritten [2026]
- NIS2 in Deutschland: 29.500 Firmen, 10 Mio Euro Strafe [2026]
- HTTPS und TLS: Wie das Schloss im Browser Sie schützt
- Cyber Resilience Act: 90 Tage Meldepflicht [2026]
- Web-Sicherheit: Der praktische Leitfaden
Häufig gestellte Fragen (FAQ)
Welchen Performance-Overhead verursacht ModSecurity?
Der Overhead hängt stark von der Konfiguration ab. Mit Paranoia-Level 1 und deaktivierter Response-Body-Inspektion liegt die zusätzliche Latenz typischerweise im einstelligen Millisekunden-Bereich pro Anfrage auf modernen Servern. Bei sehr hohem Durchsatz empfiehlt sich ein eigener Benchmark mit wrk oder h2load, der die tatsächliche Auswirkung auf die eigene Infrastruktur misst. Statische Assets lassen sich ohne Schutzeinbußen komplett aus der WAF-Inspektion ausschließen.
Kann ModSecurity 3 HTTPS-Verkehr inspizieren?
Ja. Da ModSecurity als Nginx-Modul läuft und Nginx die TLS-Terminierung übernimmt, sieht ModSecurity den entschlüsselten HTTP-Klartext. Alle HTTPS-Anfragen werden nach der TLS-Entschlüsselung durch die WAF-Engine geleitet, bevor Nginx sie an das Backend weiterreicht. Es ist daher kein separates Setup für HTTPS notwendig.
Wie oft sollte das OWASP CRS aktualisiert werden?
Ein wöchentliches Update per git pull ist für die meisten Produktionsumgebungen ausreichend. Bei aktiv ausgenutzten Schwachstellen, die das CRS-Team mit einem Notfall-Update adressiert (wie bei Log4Shell im Dezember 2021), sollte sofort aktualisiert werden. Die GitHub-Releases des CRS-Projekts per RSS-Feed oder GitHub Watch-Funktion zu verfolgen, ist empfohlen.
Was ist der Unterschied zwischen ModSecurity v2 und v3?
ModSecurity v2 ist ein Apache-Modul, das direkt in den Apache-Prozess eingebunden wird. Version 3 ist eine eigenständige C++-Bibliothek (libmodsecurity) mit einem Konnektor-Modell: Der Kern ist webserver-unabhängig, und Konnektoren für Nginx, Apache und IIS binden ihn an den jeweiligen Webserver. Diese Architektur macht v3 portabler und wartbarer. Für alle neuen Installationen ist ModSecurity 3 die richtige Wahl, insbesondere zusammen mit Nginx.
Schützt eine WAF gegen alle OWASP Top 10?
Eine WAF bietet starken Schutz gegen Injektionsangriffe (A03) und bestimmte XSS-Varianten, aber keinen vollständigen Schutz gegen alle OWASP Top 10. Broken Access Control (A01), Cryptographic Failures (A02) und Security Misconfiguration (A05) erfordern Maßnahmen auf Anwendungs- und Systemebene, die keine WAF ersetzen kann. Eine WAF ergänzt sichere Anwendungsentwicklung, ist aber kein Ersatz dafür.
Kann ModSecurity mit Cloudflare kombiniert werden?
Ja, das ist eine empfohlene Architektur: Cloudflare übernimmt DDoS-Schutz und globale Traffic-Verteilung auf Netzwerkebene, während ModSecurity auf dem Origin-Server die Anwendungsschicht schützt. Wichtig dabei: Die echte Client-IP muss über den X-Forwarded-For- oder den CF-Connecting-IP-Header korrekt an ModSecurity weitergereicht werden, damit IP-basierte Regeln und GeoIP-Lookups korrekt funktionieren.
Welches Paranoia-Level ist empfohlen?
Level 1 für neue Installationen, bei denen das False-Positive-Verhalten der eigenen Anwendung noch unbekannt ist. Level 2 für Produktionsumgebungen nach einer Tuning-Phase von 1 bis 2 Wochen im DetectionOnly-Modus. Level 3 und 4 sind für Hochsicherheitsanwendungen (Banking, Behörden, kritische Infrastruktur) gedacht und erfordern intensives Tuning, weil sie auch viele legitime Anfragen als verdächtig einstufen.
Wie lange dauert die komplette Einrichtung?
Die technische Installation (Schritte 1 bis 12) dauert auf einem frischen Ubuntu-Server etwa 45 bis 60 Minuten. Die anschließende Tuning-Phase im DetectionOnly-Modus sollte mindestens 24 Stunden dauern, bei Systemen mit komplexen Anwendungen auch 2 bis 3 Werktage. Erst nach abgeschlossenem Tuning empfiehlt sich der Wechsel in den Blocking-Modus.




