Absicherung mit mod_security und Spiderlabs OWASP

Diesen Beitrag schrieb ich 6 Jahre und 5 Monate zuvor; die nachfolgenden Ausführungen müssen heute weder genau so nach wie vor funktionieren, noch meiner heutigen Meinung entsprechen. Behalte das beim Lesen (und vor allem: beim Nachmachen!) bitte stets im Hinterkopf.

Geschätzte Lesezeit: 3 Minuten

Ein von außen erreichbarer Webserver steht immer irgendwie unter Attacke; doch in den letzten Wochen habe ich live immer mehr Fälle erfolgreicher WordPress-Hacks erlebt und debuggt, und mein Respekt vor der Sache wuchs. Denn die Attacken sind alles, von stumpfsinnig bis richtig clever, und überwiegend hat man ja nicht in der Hand, was da abgeht.

Meine ersten Versuche machte ich mit fail2ban – der Erfolg war vorhanden, aber für meinen Geschmack nicht durchschlagend genug. Da ich jedoch sicher nicht der einzige Mensch mit diesem Problem bin, machte ich mich im Netz auf die Suche – und fand das OWASP ModSecurity Core Rule Set (CRS).

„The Open Web Application Security Project (OWASP) ModSecurity Core Rule Set (CRS) is a set of generic attack detection rules for use with ModSecurity or compatible web application firewalls. The CRS aims to protect web applications from a wide range of attacks, including the OWASP Top Ten, with a minimum of false alerts.“

Die Vorgehensweise ist gar nicht so kompliziert: den apache2 mit mod_security versehen; ihn dazu bringen, die OWASP-Regeln anzuwenden; und dann Logs lesen, sehr viele Logs lesen, um das Ganze gegebenenfalls an die eigenen Belange anpassen zu können. Im ersten Anlauf habe ich es mit nginx versucht, aber das war mir für den Produktivbetrieb zu frickelig – damit angefangen, dass ich alles von Hand kompilieren musste, es ist einfach noch zu experimentell…

Die Installation von mod_security

Für den apache2 gestalten sich Installation und Inbetriebnahme dank fertig geschnürter Pakete jedoch erfreulich unkompliziert:

$ apt-get install libapache2-mod-security2
$ cd /etc/modsecurity
$ cp modsecurity.conf-recommended modsecurity.conf
$ a2enmod security2
$ a2enmod headers
$ service apache2 restart

OWASP CRS

OWASP und das, was mod_security per Default so installiert, sollen sich nicht ins Gehege geraten; deshalb werfe ich die Defaults aus dem System und ziehe mir von GitHub den master. Für den Produktivbetrieb bietet es sich eventuell an, auf das aktuelle Release zurückzugreifen – aber das überlasse ich euch.

$ cd /usr/share
$ rm -rf modsecurity-crs
$ git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git modsecurity-crs
$ cd modsecurity-crs
$ cp crs-setup.conf.example crs-setup.conf

Jetzt muss in der apache2-Konfiguration noch hinterlegt werden, dass diese Regeln zukünftig ausgewertet werden sollen. Der Inhalt meiner Datei /etc/apache2/mods-available/security2.conf gestaltet sich nun wie folgt:

## file: "/etc/apache2/mods-available/security2.conf"
 SecDataDir /var/cache/modsecurity
  IncludeOptional /etc/modsecurity/*.conf
  IncludeOptional /usr/share/modsecurity-crs/*.conf
  IncludeOptional /usr/share/modsecurity-crs/rules/*.conf 

Anpassungen der Konfiguration

Nach Installation ist zwar alles, was benötigt ist, vorhanden, aber sozusagen im Leerlauf: in /etc/modsecurity/modsecurity.conf steht SecRuleEngine auf DetectionOnly, was nichts anderes bedeutet als dass nichts aktiv geblockt wird. Aber: es ermöglicht, im Logfile zu verfolgen, was geblockt werden würde – so kann bereits vor Scharfschaltung ein fein abgestimmtes Regelwerk erarbeitet werden. Im Idealfall kommt es dann (sobald SecRuleEngine auf On gesetzt wird) nicht oder kaum zu irrtümlich geblockten Inhalten. Weitere Informationen zu den Parametern finden sich hier; die Parameter, die ich in meiner Konfiguration verändert habe, habe ich in Anhang A gelistet. Restart des apache2 ist nach Änderung der Konfiguration erforderlich, um diese Änderungen zu übernehmen; im Logfile – im Beispiel /var/log/apache2/error.log – wird ersichtlich, dass ModSecurity installiert ist und die Arbeit aufnimmt.

Betrachtung der Logfiles

Im Produktivbetrieb wird nun viel mit Logfiles jongliert. Ich zeige euch hier einen Eintrag aus dem error.log meiner Domain urban-exploring.eu, die unter fortgesetzten Attacken steht – da ist irgendwie immer was los. Der Übersichtlichkeit halber splitte ich den Eintrag zeilenweise auf:

[Mon Oct 02 10:49:24.204427 2017]
[:error]
[pid 19901]
[client 199.249.224.43:57940]
[client 199.249.224.43] ModSecurity: Access denied with code 403 (phase 2). Operator GE matched 5 at TX:anomaly_score.
[file "/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"]
[line "57"]
==> [id "949110"]
[msg "Inbound Anomaly Score Exceeded (Total Score: 5)"]
[severity "CRITICAL"]
[tag "application-multi"]
[tag "language-multi"]
[tag "platform-multi"]
[tag "attack-generic"]
[hostname "urban-exploring.eu"]
[uri "/xmlrpc.php"]
==> [unique_id "WdH9lLxEOzQAAE29EE8AAAAA"]

Markiert die id der auslösenden Regel – hier kann man sie herausgreifen, wenn man sie explizit abschalten möchte – und die unique_id: nach dieser könnt ihr in /var/log/apache2/modsec_audit.log (oder was immer ihr als SecAuditLog definiert) suchen und nähere Angaben erhalten. Schaut hier im Beispiel den Auszug für A und beachtet die Übersicht in Anhang B – das A steht für audit log header:

--1e20ae12-**A**--
[02/Oct/2017:10:49:24 +0200] WdH9lLxEOzQAAE29EE8AAAAA 199.249.224.43 57940 127.0.0.1 8080

Das F steht für die response headers – die Anfrage wurde mit Status Code 403 abgelehnt (wobei auch das konfigurierbar ist):

--1e20ae12-**F**--
HTTP/1.1 403 Forbidden
Strict-Transport-Security: max-age=63072000; includeSubdomains; preload
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Content-Length: 287
Connection: close
Content-Type: text/html; charset=iso-8859-1

Und so weiter. Es ist ein ziemlich weites Feld, und ich hab schon eine ganze Weile gebraucht, bis ich einigermaßen den Durchblick hatte – was in meinem Falle aber auch durch ein geschachteltes Proxy-Setup erschwert wurde, in dem auch der nginx kräftig herumfunkt 😎

Ausnahmen definieren

Entweder schalte ich mod_security für einen VHost explizit ab (SecRuleEngine Off) – bei einer Nextcloud-Instanz habe ich das erstmal so gehandhabt, weil mit aktiviertem ModSecurity überhaupt nichts mehr funktioniert hat – oder ich nehme explizit Regeln anhand ihrer ID von der Ausführung aus (SecRuleRemoveById). Wobei: handelt es sich hier um eine Regel, die in mehreren Kontexten Ärger bereitet, kann natürlich auch das ganze Regel-File entfernt werden.

## Fuer den gesamten VHost
 SecRuleEngine Off 

## Fuer einen Unterbereich des VHosts
 SecRuleRemoveById 931100
    SecRuleRemoveById 930120 

Fazit

Zugegeben: ich bin überrascht, was da alles aufläuft – mein Webserver ist ja lächerlich klein im Vergleich zu vielen anderen. Insofern war es eine noch spannendere Sache, das Setup auf einem shared hosting aufzuziehen: viele Webseiten, viele User, richtig viele Requests. Dort läuft es ebenfalls produktiv, jedoch unter sehr strenger Beobachtung. Ein ELK-Stack bietet sich zum Debuggen sehr an, vor allem auf dem shared hosting, man wird sonst schnell verrückt mit den ganzen Logs… Erzählt doh mal: wie handhabt ihr das so? Welche Tools setzt ihr ein? Oder ist euch das Attacken-Problem eher fremd?


Anhang A: Geänderte Parameter in modsecurity.conf

| name | default | my value | info |
| --- | --- | --- | --- |
| SecRuleEngine | DetectionOnly | On | Generelles Einschalten |
| SecStatusEngine | On | Off | Möchte nach Hause telefonieren, was ich auf diese Art unterbinde |
| SecAuditLogParts | ABDEFHIJZ | ABDEFIJZ | Was alles nach modsec_audit.log geloggt werden soll; Erklärung der Parameter siehe Anhang B |
| SecResponseBodyAccess | On | Off | Access response bodies |
| SecRequestBodyLimit | 13107200 | 1073741824 | In Bit; korrespondiert mit max_upload_size & Co., deshalb erhöht auf 128MB |
| SecRequestBodyInMemoryLimit | 131072 | 655360 | Ggf. Erhöhung in Erwägung ziehen |

Anhang B: SecAuditLogParts

| Letter | Description |
| --- | --- |
| A | Audit log header (mandatory) |
| B | Request headers |
| C | Request body |
| D | Reserved |
| E | Response body |
| F | Response headers |
| G | Reserved |
| H | Audit log trailer which contains additional data |
| I | Compact request body alternative to part C which excludes files |
| J | Reserved |
| K | Contains a list of all rules that matched for his transaction |
| Z | Final boundary (mandatory) |
Alle Bilder dieser Seite: © Marianne Spiller – Alle Rechte vorbehalten
Hintergrundbild: 1440x 530px, Bild genauer anschauen – © Marianne Spiller – Alle Rechte vorbehalten

Eure Gedanken zu „Absicherung mit mod_security und Spiderlabs OWASP“

Ich freue mich über jeden Kommentar, es sei denn, er ist blöd. Deshalb behalte ich mir auch vor, die richtig blöden kurzerhand wieder zu löschen. Die Kommentarfunktion ist über GitHub realisiert, weshalb ihr euch zunächst dort einloggen und „utterances“ bestätigen müsst. Die Kommentare selbst werden im Issue-Tracker und mit dem Label „✨💬✨ comment“ erfasst – jeder Blogartikel ist ein eigenes Issue. Über GitHub könnt ihr eure Kommentare somit jederzeit bearbeiten oder löschen.