Die Web Application Firewall (WAF) ist eine Schutzschicht für Webanwendungen. Sie liest HTTP-Anfragen und blockiert verdächtige Muster, bevor sie die Anwendung erreichen. Sie ist weder ein Ersatz für sicheren Code noch für ein Patch-Management – aber ein wirksamer zusätzlicher Filter.

Was eine WAF leistet – und was nicht

Die WAF sitzt zwischen Client und Anwendung und prüft jede Anfrage. Sie erkennt Muster, die auf bekannte Angriffe hindeuten: SQL-Injection, Cross-Site-Scripting, Pfad-Durchquerung, Kommando-Einschleusung, ungewöhnliche Anfragemethoden.

Wichtig zur Einordnung:

  • Eine WAF behebt keine Sicherheitslücke. Sie erschwert die Ausnutzung und gewinnt Zeit – mehr nicht. Wer eine Lücke hat, behebt sie.
  • Eine WAF erzeugt falsch-positive Treffer. Jede Sperre trifft auch legitime Nutzer. Die Abstimmung braucht Zeit und Geduld.
  • Eine WAF ist umgehbar. Wer weiß, wie sie arbeitet, kann Anfragen so formen, dass sie nicht erkannt werden. Das ist kein Grund, sie nicht einzusetzen – aber auch kein Grund, sich auf sie zu verlassen.

Betriebsarten

  • Umgekehrter Proxy (Reverse Proxy): Der Verkehr läuft vollständig durch die WAF. Sie kann blockieren, verändern und protokollieren. Der häufigste Aufbau – etwa ModSecurity vor nginx oder Apache, oder ein WAF-Modul im Load Balancer.
  • Inline mit nur Meldung (Detection Mode): Die WAF protokolliert Treffer, blockiert aber nichts. Das ist immer der erste Schritt – man lernt, was die eigene Anwendung auslöst, bevor man scharf schaltet.
  • Cloud-WAF: Ein Anbieter schaltet sich als Proxy davor. Vorteil: Regelpflege, Bedrohungsinformationen und Schutz vor großen Angriffen sind enthalten. Nachteil: Abhängigkeit und Weiterleitung des gesamten Verkehrs über einen Dritten.

Die Kernregelwerke

OWASP ModSecurity Core Rule Set (CRS) ist der De-facto-Standard. Es besteht aus Regelgruppen mit unterschiedlichen Risikostufen:

REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
REQUEST-901-INITIALIZATION.conf
REQUEST-905-COMMON-EXCEPTIONS.conf
REQUEST-910-IP-REPUTATION.conf
REQUEST-911-METHOD-ENFORCEMENT.conf
REQUEST-912-DOS-PROTECTION.conf
REQUEST-913-SCANNER-DETECTION.conf
REQUEST-920-PROTOCOL-ENFORCEMENT.conf
REQUEST-921-PROTOCOL-ATTACK.conf
REQUEST-930-APPLICATION-ATTACK-LFI.conf
REQUEST-931-APPLICATION-ATTACK-RFI.conf
REQUEST-932-APPLICATION-ATTACK-RCE.conf
REQUEST-933-APPLICATION-ATTACK-PHP.conf
REQUEST-941-APPLICATION-ATTACK-XSS.conf
REQUEST-942-APPLICATION-ATTACK-SQLI.conf
REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf
REQUEST-944-APPLICATION-ATTACK-JAVA.conf
RESPONSE-950-DATA-LEAKAGES.conf
RESPONSE-951-DATA-LEAKAGES-SQL.conf
RESPONSE-952-DATA-LEAKAGES-JAVA.conf
RESPONSE-953-DATA-LEAKAGES-PHP.conf
RESPONSE-954-DATA-LEAKAGES-IIS.conf
RESPONSE-959-BLOCKING-EVALUATION.conf
RESPONSE-980-CORRELATION.conf

Jede Regel hat einen Score. Läuft die Summe der Treffer einer Anfrage über eine Grenze (Anomaly Score Threshold), wird die Anfrage blockiert. Dieses Punktesystem ist die Stärke des CRS: Eine einzelne unauffällige Abweichung wird nicht sofort blockiert, mehrere zusammen schon.

Einrichtung mit nginx und ModSecurity

# Installation (Debian/Ubuntu)
apt install libnginx-mod-http-modsecurity modsecurity-crs

# /etc/nginx/modsecurity.conf (oder ueber include einbinden)
SecRuleEngine DetectionOnly          # ERST nur melden!
SecRequestBodyAccess On
SecResponseBodyAccess Off
SecAuditEngine RelevantOnly
SecAuditLog /var/log/nginx/modsec_audit.log

# CRS einbinden
Include /etc/modsecurity/crs/crs-setup.conf
Include /etc/modsecurity/crs/rules/*.conf

# Schwellwerte anpassen
SecAction "id:900000,phase:1,nolog,pass,t:none,setvar:tx.inbound_anomaly_score_threshold=5"
SecAction "id:900110,phase:1,nolog,pass,t:none,setvar:tx.outbound_anomaly_score_threshold=4"
# nginx: ModSecurity aktivieren
server {
    listen 443 ssl;
    server_name app.example.org;

    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity.conf;

    location / {
        proxy_pass http://webapp;
    }
}

Falsch-Positive in den Griff bekommen

Das ist die eigentliche Arbeit. Ohne sie wird die WAF nach zwei Wochen abgeschaltet, weil sie legitime Nutzer blockiert.

# 1. Im Detection-Only-Modus laufen lassen - mindestens eine Woche
#    mit echtem Verkehr.

# 2. Treffer auswerten: Welche Regeln und welche Pfade?
grep -o 'id "[0-9]*"' /var/log/nginx/modsec_audit.log | sort | uniq -c | sort -rn | head -20
grep -o '"uri":"[^"]*"' /var/log/nginx/modsec_audit.log | sort | uniq -c | sort -rn | head -20

# 3. Gezielt ausnehmen - so eng wie moeglich
# /etc/modsecurity/crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

# Eine Regel auf einem bestimmten Pfad abschalten
SecRule REQUEST_URI "@beginsWith /api/upload" \
  "id:1001,phase:1,pass,nolog,ctl:ruleRemoveTargetById=942100;ARGS:inhalt"

# Ganz bestimmte Regel fuer einen Pfad deaktivieren
SecRule REQUEST_URI "@streq /admin/editor" \
  "id:1002,phase:1,pass,nolog,ctl:ruleRemoveById=941100"

# Einen Parameter von der Pruefung ausnehmen (haeufig bei Rich-Text-Feldern)
SecRuleUpdateTargetById 942100 "!ARGS:html_inhalt"
SecRuleUpdateTargetById 941110 "!ARGS:beschreibung"
SecRuleUpdateTargetById 949110 "!ARGS:json_payload"

# Parameter-Werte dekodieren, die Base64 enthalten
SecRule REQUEST_URI "@beginsWith /api/" \
  "id:1003,phase:2,pass,nolog,ctl:ruleRemoveById=920270"

Häufige Ursachen für Falschmeldungen: Rich-Text-Editoren, die HTML senden; JSON-Nutzlasten mit Anführungszeichen und Klammern; Datei-Uploads mit Binärinhalt; Anwendungen, die Base64-kodierte Parameter nutzen; doppelt kodierte Zeichen (etwa %253C); und APIs, die Anweisungen wie SELECT oder UNION legitim als Dateninhalt übertragen.

Der Weg zur scharfen Schaltung

  1. Detection Only mit echtem Verkehr laufen lassen – mindestens eine Woche, inklusive der Nutzungsmuster, die selten auftreten.
  2. Ausnahmen dokumentieren. Jede Ausnahme braucht eine Begründung und ein Datum. Eine Liste ohne Dokumentation wird nie wieder aufgeräumt.
  3. Blockiergrenze schrittweise senken. Von „nur melden“ zu „ab hohem Punktwert blockieren“ zu „ab mittlerem Punktwert“. Jede Stufe mit Beobachtung.
  4. Ausnahmeregeln regelmäßig prüfen. Eine Ausnahme für eine Funktion, die es nicht mehr gibt, ist eine offene Lücke.
  5. Meldungen ins Monitoring. Die Anzahl der Treffer und Blockierungen über die Zeit zeigt, ob die WAF wirkt und ob jemand systematisch probiert.

Weitere Schutzschichten

Eine WAF ist ein Baustein. Wirksam wird sie im Verbund:

  • Content Security Policy: Eine Kopfzeile, die dem Browser sagt, welche Skriptquellen erlaubt sind. Die wirksamste Verteidigung gegen Cross-Site-Scripting – weil sie im Browser greift, nicht am Server.
  • Ratenbegrenzung: Anmeldungen und teure Endpunkte begrenzen. Viele Angriffe scheitern schon daran.
  • Anfragegrößen begrenzen: client_max_body_size in nginx. Ohne Grenze kann eine riesige Anfrage den Server lahmlegen.
  • Zeitlimits: proxy_read_timeout und ähnliche. Ohne sie binden langsame Anfragen Ressourcen.
  • Sicherheits-Kopfzeilen: Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, Permissions-Policy.
  • Fehlerausgaben unterdrücken: Stack-Traces und Versionsangaben sind eine Einladung. Ausführliche Fehler nur im Protokoll, nie im Browser.

Verwandte Grundlagen: Content Security Policy, Server härten, SQL-Injection, Firewall.