Discourse + Web Application Firewall (WAF) mod_security

Welche WAF wird empfohlen, um vor Discourse zu laufen?

Ich habe kürzlich erfolgreich die im Discourse-Docker-Container installierte nginx-Konfiguration so angepasst, dass sie ModSecurity und das OWASP (Open Web Application Security Project) CRS (Core Rule Set) enthält.

Bisher sind meine Tests hervorragend, und ModSecurity scheint mit Discourse out-of-the-box sehr gut zu funktionieren.

Wie sind die Erfahrungen anderer Benutzer mit WAFs und Discourse? Haben Sie andere Empfehlungen als ModSecurity?

Ein Hinweis dazu, warum WAFs wichtig sind: Sie bieten umfassenden Schutz vor 0-Day-Schwachstellen, nicht nur für die Webanwendung selbst, sondern auch für den gesamten Abhängigkeitsstack der Webanwendung.

Mir wurde darauf hingewiesen, dass das Discourse-Team ein Bug-Bounty-Programm hat – das ist großartig!

…aber natürlich gibt es keinen 100% sicheren Code. Fehler passieren, und es muss nicht einmal der Fehler Ihres eigenen Teams sein, der eine kritische Schwachstelle in Ihr Projekt einschleust.

Betrachten Sie beispielsweise die jüngste Geschichte mit CVE-2019-11043: ein Fehler in php-fpm, der als Remote-Code-Ausführung auf Servern mit anfälligen Versionen von php-fpm und nginx ausgenutzt werden konnte.

CVE-2019-11043 lässt sich jedoch vollständig dadurch mildern, dass Anfragen blockiert werden, die Wagenrückläufe oder Zeilenumbrüche enthalten:

Dies ist nur ein Beispiel dafür, wie eine Installation einer Webanwendung durch eine kritische Schwachstelle angegriffen werden kann, selbst wenn der Code der Webanwendung selbst keine Fehler aufweist. Im Fall von Discourse wird während der Docker-Installation eine große Menge externer Software eingebunden, die Discourse in Zukunft anfällig machen könnte.

Im oben genannten Fall blockiert das ModSecurity CRS jedoch bereits Anfragen mit Zeilenumbrüchen und Wagenrückläufen – und schützt so ansonsten anfällige Webserver vor CVE-2019-11043 vor dem 0. Tag.

Solche Schwachstellen werden die ganze Zeit über entdeckt. Die Nutzung einer WAF wie ModSecurity für Webanwendungen bietet erhebliche Vorteile.

Das ist eine schlechte Idee und wird nicht empfohlen. Der Nutzen einer solchen Vorgehensweise für eine JavaScript-App ist extrem begrenzt und fügt Ihrer Hosting-Umgebung erhebliche Komplexität hinzu.

Zusammenhang: Ich habe gerade diese Anleitung von @joelradon gefunden, die erklärt, wie man Discourse mit der NAXSI WAF in nginx vor dem Discourse Docker-Container installiert:

Das ist nicht mehr supportbar als das, was du oben fragst.

Falls es hilft, kann ich dort auch ein Tag für „nicht unterstützt

Ich denke, der Wunsch nach einem magischen Gerät, das Probleme automatisch abmildert, ist bei der Discourse-Einrichtung etwas fehlgeleitet. Wir haben ein Bountysystem und beheben Fehler in Discourse innerhalb weniger Stunden nach ihrer Meldung. Seiten führen standardmäßig tests-passed aus, was im heutigen Fall Commits von heute enthält.

Natürlich macht eine WAF Sinn, wenn Sie Software betreiben, die vor Jahren kompromittiert wurde und Sie aus bestimmten Gründen keine Möglichkeit haben, ein Upgrade durchzuführen – sie könnte Sie dann retten. Im Fall von Discourse halte ich sie jedoch bestenfalls für fehlgeleitet.

Ich konnte meine Änderungen an der nginx-ModSecurity-Konfiguration erfolgreich über mehrere launcher rebuild app-Durchläufe hinweg beibehalten, und zwar wie folgt:

Zuerst aktualisieren wir die lokale Kopie von install-nginx, die aus dem discourse_docker-Repository stammt und nach /var/discourse/ geklont wurde.

cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig

# Füge einen Block hinzu, um das ModSecurity-nginx-Modul kurz vor dem Herunterladen der nginx-Quellen auszuchecken
grep 'ModSecurity' install-nginx || sed -i 's%\(curl.*nginx\.org/download.*\)%# mod_security\napt-get install -y libmodsecurity-dev modsecurity-crs\ncd /tmp\ngit clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git\n\n\1%' install-nginx

# Aktualisiere die Konfigurationszeile, um das oben ausgecheckte ModSecurity-Modul einzubeziehen
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx

# Füge eine Zeile zum Bereinigungsbereich hinzu
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx

Beachten Sie, dass die für die Ausführung des install-nginx-Skripts zuständige Dockerfile beim Erstellen des Images ausgeführt wird. Das Image wird jedoch nur vom Discourse-Team erstellt, bevor es auf Docker Hub hochgeladen wird. Wenn der Discourse-Befehl ./launcher rebuild app ausgeführt wird, wird (falls Updates verfügbar sind) ein docker pull ausgelöst, der das neueste Discourse-Docker-Image von Docker Hub herunterlädt. Dies führt erneut nicht zu einem Neuaufbau des Images, zur Ausführung der Dockerfile oder zur Ausführung des oben geänderten install-nginx-Skripts.

Der einzige Weg (den ich kenne), um das aktualisierte install-nginx-Bash-Skript zur Ausführung zu bringen (das von der Dockerfile ausgeführt wird), besteht darin, dass Docker ein neues Image erstellt. Beispielsweise löst dies den Build eines neuen Images namens discourse_modsecurity aus – das unter Verwendung des lokal modifizierten install-nginx-Skripts erstellt wird:

docker build --tag 'discourse_modsecurity' /var/discourse/image/base/

Leider konnte ich keinen Weg finden, launcher anzuweisen, ein benutzerdefiniertes Image zu verwenden (die Angabe eines run-image verwendet das angegebene Image direkt, ohne die Vorlagen darauf auszuführen – wie es erforderlich ist, um nginx tatsächlich zu konfigurieren [anstatt nur zu installieren]). Daher ersetzen wir die im launcher-Skript definierte Variable image, um unser neues lokales Docker-Image namens discourse_modsecurity zu verwenden:

# Ersetze die Zeile "image="discourse/base:<version>" durch 'image="discourse_modsecurity"'
grep 'discourse_modsecurity' launcher || sed --in-place=.`date "+%Y%m%d_%H%M%S"` '/base_image/! s%^\(\s*\)image=\(.*\)$%#\1image=\2\n\1image="discourse_modsecurity"%' /var/discourse/launcher

Nun fügen wir eine neue Vorlagendatei hinzu, um unsere nginx-Konfigurationen so einzurichten, dass sie die erforderlichen ModSecurity-Dateien/Blöcke enthalten:

cat << EOF > /var/discourse/templates/web.modsecurity.template.yml
run:
  - exec:
     cmd:
       - sudo apt-get install -y modsecurity-crs
       - cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
       - sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf
       - sed -i 's^\(\s*\)[^#]*SecRequestBodyInMemoryLimit\(.*\)^\1#SecRequestBodyInMemoryLimit\2^' /etc/modsecurity/modsecurity.conf
       - sed -i '/nginx/! s%^\(\s*\)[^#]*SecAuditLog \(.*\)%#\1SecAuditLog \2\n\1SecAuditLog /var/log/nginx/modsec_audit.log%' /etc/modsecurity/modsecurity.conf

  - file:
     path: /etc/nginx/conf.d/modsecurity.include
     contents: |
        ################################################################################
        # File:    modsecurity.include
        # Version: 0.1
        # Purpose: Defines mod_security rules for the discourse vhost
        #          This should be included in the server{} blocks nginx vhosts.
        # Author:  Michael Altfield <michael@opensourceecology.org>
        # Created: 2019-11-12
        # Updated: 2019-11-12
        ################################################################################
        Include "/etc/modsecurity/modsecurity.conf"
        
        # OWASP Core Rule Set, installiert aus dem Paket 'modsecurity-crs' in Debian
        Include /etc/modsecurity/crs/crs-setup.conf
        Include /usr/share/modsecurity-crs/rules/*.conf

  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /server.+{/
     to: |
       server {
         modsecurity on;
         modsecurity_rules_file /etc/nginx/conf.d/modsecurity.include;

EOF
```\n
Fügen Sie diese Vorlage (templates/web.modsecurity.template.yml) zum `templates`-Block der YAML-Konfigurationsdatei Ihrer App hinzu, sodass sie ungefähr so aussieht:

[root@osestaging1 discourse]# vim /var/discourse/containers/app.yml

[root@osestaging1 discourse]# grep -A 6 ‘templates:’ /var/discourse/containers/app.yml
templates:

  • “templates/postgres.template.yml”
  • “templates/redis.template.yml”
  • “templates/web.template.yml”
  • “templates/web.ratelimited.template.yml”
  • “templates/web.socketed.template.yml”
  • “templates/web.modsecurity.template.yml”
    [root@osestaging1 discourse]#

Wenn Sie jetzt die Discourse-Docker-App neu aufbauen, wird das neue Docker-Image `discourse_modsecurity` mit nginx und ModSecurity verwendet, und nginx wird so konfiguriert, dass es das OWASP CRS nutzt.

/var/discourse/launcher rebuild app

Ich stimme Ihnen zu, dass ModSecurity oder ähnliche WAFs kein Allheilmittel sind.

Aber ich kenne (zumindest?) eine Schwachstelle in RoR, die Discourse betraf, die durch einen modSecurity-ähnlichen Mechanismus abgewehrt worden wäre.

Als wir diesen Fehler behoben haben, sahen wir in unseren Logs, dass er in der Wildnis mindestens auf einem unserer Foren ausgenutzt wurde, bevor die CVE öffentlich bekannt und gepatcht war. Dies führte zwar nicht zur Offenlegung von Informationen, aber das lag nur daran, dass wir einige Dinge anders handhabten als bei einer Standardinstallation (also Glück).

Ich bin mir jedoch nicht sicher, ob die zusätzliche Komplexität den zusätzlichen Sicherheitsgewinn aufwiegt.

Ich vergleiche WAFs mit signaturbasierten Virenscannern, die meiner Meinung nach in Umgebungen mit einer begrenzten Angriffsfläche (z. B. Ihre Nicht-Windows-Server) nicht sehr nützlich sind.

Sie werden nicht alles abfangen, aber sie werden (theoretisch) gängige Angriffsmuster (z. B. SQLI) und bekannte Exploits (z. B. die oben genannte RoR-Schwachstelle) über eine Reihe von Softwarelösungen hinweg erkennen.

Ich kann den Nutzen sehen, sie besonders in einer Umgebung (Unternehmen) einzusetzen, in der eine Vielzahl von Anwendungen läuft, die Gott weiß was ausführen, und man sicherstellen muss, dass jede Anwendung vor diesen Exploits geschützt ist, ohne sich um jede einzelne kümmern zu müssen – das wandelt ein Problem der Größe NxM in eines der Größe N+M um.

Ob es sich für Ihre Website lohnt, sie einzusetzen, ist eine andere Frage und Teil der Risiko-Nutzen-Analyse (Risiko von Ausfällen vs. Nutzen des Schutzes), die Sie selbst durchführen müssen.