Warum ModSecurity standardmäßig auf jeden Kundenserver kommt
ModSecurity, zusammen mit dem OWASP Core Rule Set (CRS), kommt auf jeden Server, den ich aufsetze, bevor ich überhaupt weiß, welche Anwendung später darauf laufen wird. Das klingt vielleicht rückwärts, wie konfiguriert man eine Web Application Firewall für eine Anwendung, die noch nicht existiert, aber genau das ist der Punkt. CRS ist nicht auf eine spezifische Anwendung abgestimmt, sondern auf die Art von Anfragen, die automatisierte Angriffe an jeden Server senden, in der Annahme, dass irgendetwas, irgendwo, dafür anfällig sein könnte.
Was es tatsächlich abfängt
Auf praktisch jedem Webserver mit hochgedrehtem Logging sieht man einen konstanten Strom von Anfragen, die mit der eigentlichen Anwendung gar nichts zu tun haben: Versuche, auf /wp-admin zuzugreifen, auf einem Server, der gar kein WordPress betreibt, SQL-Injection-Payloads in Query-Parametern von Seiten, die keine Query-Parameter entgegennehmen, Path-Traversal-Versuche (../../etc/passwd) gegen statische Dateipfade, Anfragen mit Payloads, die Schwachstellen in Software ausnutzen sollen, die nie installiert wurde. Keine davon muss erfolgreich sein, um ein Problem zu sein, sie sind im besten Fall Rauschen und im schlimmsten Fall ein echtes Risiko, falls auch nur eine installierte Software zufällig zu dem passt, wonach gesucht wird.
CRS erkennt die Muster dahinter, nicht spezifische Anwendungsschwachstellen. Ein SQL-Injection-Versuch sieht strukturell wie ein SQL-Injection-Versuch aus, egal ob er auf eine maßgeschneiderte PHP-Anwendung zielt, ein WordPress-Plugin, oder eine statische Seite ganz ohne Datenbank (wo er ohnehin scheitern wird, aber trotzdem eine Probe ist, von der man wissen sollte). Diese strukturelle Erkennung ist es, was es ohne anwendungsspezifische Konfiguration nützlich macht.
Immer erst der Detection-Modus
Der häufigste Grund, warum Leute ModSecurity komplett abschalten, ist ein False Positive, das legitimen Traffic blockiert, meist entdeckt, wenn ein Kunde ein Formular nicht absenden kann, weil seine Eingabe zufällig zu einem Regelmuster passt. Die Lösung dafür ist nicht, ModSecurity zu deaktivieren, sondern es zuerst im Detection-Modus zu betreiben:
# modsecurity.conf
SecRuleEngine DetectionOnly
In diesem Modus protokolliert ModSecurity, was es blockiert hätte, ohne tatsächlich etwas zu blockieren. Ein bis zwei Wochen in diesem Modus gegen echten Traffic zu laufen, bringt alle False Positives für die spezifische Anwendung zutage, die sich dann mit gezielten Ausnahmeregeln adressieren lassen, bevor in den Blocking-Modus gewechselt wird:
SecRuleEngine On
Dieser zweistufige Rollout macht den Unterschied zwischen "ModSecurity hat einen Kunden blockiert und wurde komplett deaktiviert, sodass der Server gar keine WAF mehr hat" und "ModSecurity hat ein paar abgestimmte Ausnahmen und blockiert aktiv alles andere".
Ausnahmen abzustimmen ist normal, kein Scheitern
CRS bringt eine Einstellung namens "Paranoia Level" mit, höhere Stufen fangen mehr ab, produzieren aber mehr False Positives. Die Standardstufe ist ein vernünftiger Ausgangspunkt, und jede darüber hinaus nötige Ausnahme ist normalerweise eng begrenzt, auf eine bestimmte Rule-ID, für einen bestimmten URL-Pfad, statt breite Schutzkategorien komplett zu deaktivieren:
SecRuleRemoveByIdWithMsg "rule message text" "specific-form-endpoint"
Eine Handvoll Ausnahmen für die Eigenheiten einer Anwendung (zum Beispiel ein Rich-Text-Editor, der legitim HTML-ähnlichen Inhalt sendet) ist völlig normal und untergräbt nicht den Schutz für alles andere auf dem Server. Das Ziel ist nicht null Ausnahmen, sondern eine WAF, die tatsächlich aktiv ist und blockiert, mit der kleinen Anzahl von Ausnahmen, die eine Anwendung wirklich braucht.
Der Performance-Preis ist kleiner als die Alternative
ModSecurity bringt tatsächlich Overhead mit sich, jede Anfrage wird gegen das Regelwerk geprüft, bevor sie die Anwendung erreicht. In der Praxis ist dieser Overhead für die meisten Anfragen klein im Vergleich zur eigenen Verarbeitungszeit der Anwendung, und er skaliert mit der Größe des Regelwerks, nicht mit der Komplexität der Anwendung. Verglichen mit der Alternative, einem Server ohne generischen Schutz gegen die ständige Grundlast automatisierter Probes, spricht der Tradeoff klar dafür, es eingeschaltet zu lassen.
Warum "standardmäßig" wichtig ist
Der Grund, warum das auf jeden Server kommt, bevor überhaupt entschieden ist, welche Anwendung läuft, ist, dass der Schutz, den es bietet, nicht davon abhängt, die Anwendung zu kennen. Bis eine Anwendung deployed ist und vielleicht ein Security-Review stattfindet, war ein Server ohne WAF bereits all dem ausgesetzt, was ihn probt, seit er eine IP-Adresse bekommen hat. Mit ModSecurity vom ersten Tag an im Detection-Modus zu starten, und dann in den Blocking-Modus zu wechseln, sobald die spezifischen Traffic-Muster der Anwendung verstanden sind, bedeutet, dass die Lücke zwischen "Server existiert" und "Server hat einen Basisschutz" effektiv null ist, statt davon abzuhängen, wie lange es dauert, bis jemand daran denkt, ihn hinzuzufügen.