Written on 27. Dezember 2022

NGINX als Reverse Proxy mit ModSecurity und OWASP Ruleset auf Debian

Ich habe mein Heimnetzwerk in drei separate Bereiche unterteilt: ein Datencenter, eine DMZ (demilitarisierte Zone) und ein internes Client-Netzwerk. Um zu verhindern, dass meine Clients direkten Zugriff auf das Datencenter haben, habe ich einen NGINX-Reverse-Proxy in der DMZ eingerichtet. Dies ermöglicht sowohl Clients im Netzwerk als auch denen aus dem WAN (Wide Area Network) eine Verbindung. Zudem kann ich alle Websites mit einem Let’s Encrypt-Zertifikat absichern.

In den nächsten Tagen plane ich, einen Artikel über die Konfiguration von Apache2 als Reverse-Proxy mit ModSecurity und dem OWASP-Regelwerk zu veröffentlichen.

Installation

Um NGINX und Certbot aus dem Standard-Repository auf einem Debian-basierten Betriebssystem zu installieren, kann der Paketmanager apt verwendet werden:

apt update 
apt install nginx certbot python3-certbot-nginx

Certbot Wildcard Zertifikatanforderung

Um ein Wildcard-Zertifikat für die Domain mit einer DNS-Challenge und Certbot anzufordern, müssen die folgenden Schritte ausgeführt werden:

certbot certonly --manual --preferred-challenges=dns --server https://acme-v02.api.letsencrypt.org/directory -d *.stangneth.com

Man muss den Anweisungen von Certbot zum Erstellen eines TXT-Eintrags in den DNS-Einstellungen folgen. Dies beinhaltet normalerweise das Einloggen in die Verwaltungskonsole des Domainanbieters und das Hinzufügen eines neuen TXT-Eintrags mit dem von Certbot bereitgestellten Wert.

Sobald der TXT-Eintrag hinzugefügt wurde, kehrt man zum Terminal zurück und drückt Enter, um den Zertifikatsanforderungsprozess fortzusetzen.

Certbot überprüft, ob der TXT-Eintrag korrekt hinzugefügt wurde und stellt bei Erfolg ein Wildcard-Zertifikat für die Domain aus.

Bitte beachten, dass dieser Prozess je nach Domainanbieter und den von ihm angebotenen DNS-Verwaltungstools variieren kann. Möglicherweise muss man die Dokumentation oder die Support-Ressourcen des Anbieters zu Rate ziehen.

Es wird gespeichert unter:

/etc/letsencrypt/live/stangneth.com/

NGINX konfigurieren

Starten und aktivieren von NGINX:

systemctl start nginx
systemctl enable nginx

Prüfen, ob NGINX ohne Fehler läuft:

systemctl status nginx

Um die Standardseite in NGINX zu deaktivieren, muss der symbolischen Link zur Standard-Site-Konfigurationsdatei aus dem Verzeichnis sites-enabled entfernt werden. Dieses Verzeichnis wird von NGINX verwendet, um zu bestimmen, welche Site-Konfigurationen beim Start des Servers aktiviert und verwendet werden soll. Deaktivieren der Standardseite:

unlink /etc/nginx/sites-enabled/default

Wechseln in das sites-available Verzeichnis und eine eigene Konfiguration anlegen:

cd /etc/nginx/sites-enabled/
vi 001-example.stangneth.com.conf

Um alle Standardanfragen auf Port 80 und Port 443 (HTTP und HTTPS) abzufangen und in NGINX einen 404-Fehler zurückzugeben, kann die folgende Konfiguration verwendet werden:

server {
	listen 80 default_server;
	server_name _;
	return 404;
}
server {
	listen 443 ssl default_server;
	server_name _;
	ssl_certificate /etc/letsencrypt/live/stangneth.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/stangneth.com/privkey.pem;
	return 404;
}

Diese Konfiguration richtet zwei Server-Blöcke ein, einen für Port 80 und einen für Port 443. Die Direktive default_server gibt an, dass diese Blöcke alle Standardanfragen abfangen sollen, die mit keinem anderen Server-Block übereinstimmen. Die Direktive return wird verwendet, um dem Client einen 404-Fehler zurückzugeben.

Um alle HTTP-Anfragen auf HTTPS umzuleiten, kann die folgende Konfiguration verwendet werden:

server {
	listen 80;

	server_name example.stangneth.com;
	rewrite ^ https://$host$request_uri permanent;
}

Schließlich können Sie den Teil für die erste Website auf Port 443 hinzufügen:

server {
	listen 443 ssl;

	server_name example.stangneth.com;                              
   
	ssl_certificate /etc/letsencrypt/live/stangneth.com/fullchain.pem;       
	ssl_certificate_key /etc/letsencrypt/live/stangneth.com/privkey.pem;     
	ssl_session_cache builtin:1000 shared:SSL:10m;                        
	ssl_protocols TLSv1.1 TLSv1.2;                                  
	ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; 
	ssl_prefer_server_ciphers on;                                         
   
	access_log /var/log/nginx/access.log;                                 

	location / {
		allow 172.16.0.0/24;

		proxy_pass https://172.16.0.234;
		proxy_read_timeout 90;
	}
}

Ich habe ein allow für einen bestimmten IP-Bereich hinzugefügt, sodass nicht jeder aus dem Internet auf die Seite zugreifen kann. Dies kann nützlich für Ressourcen sein, die ein offizielles Zertifikat von Let’s Encrypt haben sollen, aber nicht vom Internet aus erreichbar sein müssen. In meinem Fall handelt es sich um ein MediaWiki.

Die Konfiguration für die Webseite aktivieren:

ln -s /etc/nginx/sites-avaialable/001-example.stangneth.com.conf /etc/nginx/sites-enabled/001-example.stangneth.com.conf

NGINX neustarten und prüfen, ob die Webseite erreichbar ist (DNS prüfen!):

service nginx configtest
systemctl restart nginx
systemctl status nginx

ModSecurity installieren

Abhängigkeiten installieren:

apt install -y apt-utils autoconf automake build-essential git libcurl4-openssl-dev libgeoip-dev liblmdb-dev libpcre++-dev libtool libxml2-dev libyajl-dev pkgconf wget zlib1g-dev

Das Verzeichnis wechseln zu /usr/local/src und das git repo klonen:

cd /usr/local/src
git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity

In das Verzeichnis wechseln und ModSecurity installieren:

cd ModSecurity/
git submodule init
git submodule update
./build.sh
./configure
make
make install

Als nächstes den NGINX modsecurity connector von git klonen:

cd ..
git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git

Prüfen, welche NGINX Version installiert ist:

nginx -v

In diesem Fall 1.18.0. Den passenden Source Code herunterladen:

wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar zxvf nginx-1.18.0.tar.gz

Jetzt das modsecurity-nginx module kompilieren und es in das module Verzeichnis kopieren:

cd nginx-1.18.0/
./configure --with-compat --add-dynamic-module=../ModSecurity-nginx
make modules
cp /usr/local/src/nginx-1.18.0/objs/ngx_http_modsecurity_module.so /etc/nginx/modules/

In der nginx.conf das Modul laden:

vi /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
load_module /etc/nginx/modules/ngx_http_modsecurity_module.so;

NGINX neustarten und den Status prüfen:

systemctl restart nginx
systemctl status nginx

ModSecurity konfigurieren

Ein neues Verzeichnis für die ModSecurity Konfigurationsdateien anlegen:

mkdir /etc/nginx/modsec

Download der Standard modsecurity.conf-recommed vom SpiderLabs git repo:

wget -P /etc/nginx/modsec/ https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
mv /etc/nginx/modsec/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf

Um sicher zu sein, das ModSecurity die unicode.mapping Datei finden kann kopiert man es nach /etc/nginx/modsec:

cp /usr/local/src/ModSecurity/unicode.mapping /etc/nginx/modsec/

In der modsecurity.conf den Eintrag SecRuleEngine ändern von „DetectionOnly“ zu „On“:

vi /etc/nginx/modsec/modsecurity.conf

Eine .conf Datei anlegen, wo es möglich ist bestimmte Webseitkonfigurationen anzupassen. In diesem Fall das ModSecurity laden:

vi /etc/nginx/modsec/main.conf
Include "/etc/nginx/modsec/modsecurity.conf"

OWASP Ruleset

Herunterladen des neusten OWASP coreruleset vom git repo:

cd /usr/local/src
wget https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/v3.0.2.tar.gz
tar -xzvf v3.0.2.tar.gz
cd owasp-modsecurity-crs-3.0.2/

Kopieren der Beispiel Konfigurationsdatei:

cp crs-setup.conf.example crs-setup.conf

Öffnen der main.conf und laden des ruleset:

# OWASP CRS v3 rules
Include /usr/local/src/owasp-modsecurity-crs-3.0.2/crs-setup.conf
Include /usr/local/src/owasp-modsecurity-crs-3.0.2/rules/*.conf

ModSecurity für bestimmte Webseiten aktivieren

Um ModSecurity für eine bestimmte Webseite zu aktivieren, passt man die .conf Datei an:

vi /etc/nginx/sites-available/001-example.stangneth.com.conf
server {
	listen 443 ssl;

	server_name example.stangneth.com;                              

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

	modsecurity_rules '
            SecRuleRemoveById 949110
        ';

Die SecRuleRemoveById section ist ein Beispiel. Es wird oft passieren das Webseiten nicht das komplette Ruleset benötigen/akzeptieren. Es wird zu false/postive Alarmen kommen.

Es ist möglich zu prüfen, welche Regel gezogen wurde:

tail -f /var/log/nginx/error.log

Ein output kann wie im folgenden Beispiel aussehen:

2022/12/27 14:38:39 [error] 1155#1155: *18 [client 172.16.0.123] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `5' ) [file "/usr/local/src/owasp-modsecurity-crs-3.0.2/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "44"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [data ""] [severity "2"] [ver ""] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "172.16.0.233"] [uri "/api/v1/tickets/14"] [unique_id "167188911882.664343"] [ref ""], client: 172.16.0.123, server: example.stangneth.com, request: "PUT /api/v1/tickets/14?all=true HTTP/1.1", host: "example.stangneth.com", referrer: "https://example.stangneth.com/"

Hier war es notwendig die [id „949110“] von der Konfiguration DIESER einen Webseite zu entfernen. Bei anderen Webseiten muss das nicht der Fall sein.

Keine Kommentare zu NGINX als Reverse Proxy mit ModSecurity und OWASP Ruleset auf Debian

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert