Ein Reverse Proxy hat wesentliche Vorteile gegenüber direkt von außen erreichbaren Webseiten:

  1. Webserver sind nicht über IP Adresse erreichbar.
  2. Durch die Weiterleitung per Namensauflösung benötigt man nur eine externe IP und kann damit mehrere Webserver nach außen hin anbieten.
  3. Auf dem Reverse-Proxy können zerntral Sicherheitsfeatures implementiert werden.

Vorraussetzungen

Die Anleitung ist für Debian 11. Andere Distributionen können bei Pfaden und Programmpaketen oder Programmnamen leicht abweichen. Apache2 wurde vom Paketmanager vorinstalliert.

Debian hat kein sudo vorinstalliert. Die unten gezeigten Kommandos müssen aber mit root-Rechten ausgeführt werden. Also entweder sudo installieren oder als root anmelden und bei den Befehlen das vorangestellte sudo weg lassen.

Referenzen

https://samhobbs.co.uk/2015/09/example-whitelisting-rules-apache-modsecurity-and-owasp-core-rule-set

https://www.oreilly.com/content/how-to-tune-your-waf-installation-to-reduce-false-positives/

https://www.netnea.com/cms/apache-tutorials/

Überlegungen

Webzugriff der Server hinter dem Reverseproxy

Ein Reverseproxy behandelt alle Anfragen von außen an eine Webseite. Nun betten Webseiten teilweise auch externe Informationen von anderen URL’s ein, prüfen auf Updates oder kommunizieren mit einem Marketplace. Solche Anfragen, die dann von der Webseite selbst aus richtung Internet gehen, müssen für das Funktionieren einer Webseite erlaubt werden. Hier wären also zusätzliche Freigaben auf der Firewall nötig. Ich gehe davon aus, dass bei einem Reversproxy Konstrukt eine Gateway Firewall im Einsatz ist.

HTTP oder SSL Termination

Soll zwischen dem Reverseproxy und den dahinter liegenden Servern über SSL kommuniziert werden oder reicht HTTP aus, da wir uns bereits im internen Netzwerk befinden?

Oft erscheint die Konfiguration von SSL als zusätzliche Last und viele belassen es bei HTTP. Das ist aber grundlegend falsch. Ganz klar sollte auch hinter dem Reverseproxy SSL gesprochen werden. Eine unverschlüsselte Kommunikation ist in jedem Fall überall zu vermeiden. Da ist sich die Sicherheitcommunity zumindest einig.

Logging

Auf dem Reverseproxy selbst werden die eingehenden Verbindungen mit der richtigen RemoteIP geloggt. Auf den Servern hinter dem Remoteproxy wird in der Standardkonfiguration die IP das Reverseproxy geloggt. Wer also auch auf den Servern hinter dem Reverseproxy die RemoteIP des Clients sehen will, muss das Loggen von RemoteIP’s konfigurieren. Das geht bei Apache mit mod_remote. Der Reversoproxy bringt die dafür nötigen über mod_proxy mit ein:

https://httpd.apache.org/docs/current/mod/mod_proxy.html#x-headers

Debian vorbereiten

Zusatzpakete installieren (optional)

Vim ist das bessere vi und ich persönlich bevorzuger den gegenüber nano

Die resolvconf benötigt man, um unter /etc/network/interfaces auch DNS-Server angeben zu können. Anstonsten sind die fest unter /etc/resolv.conf hinterlegt.

sudo apt install vim resolvconf

Apache installieren (falls noch nicht installiert)

sudo apt install apache2

Apache konfigurieren

Module aktivieren

sudo a2enmod ssl
sudo a2enmod mod_proxy
sudo a2enmod mod_proxy_http

Konfiguration anpassen

Zuerst deaktivieren wir die Standardkonfiguration von Apache:

sudo a2dissite *

Dann erstellen wir unsere eigene Seitenkonfiguration.

vi /etc/apache2/sites-available/revproxy.conf

Hier eine Beispielkonfiguration. Das Wissen um SSL Zertifikate und wie man die nutzt setze ich hier mal vorraus. Dazu gibt es genug Tutorials im Netz.

Mit der ProxyPass und ProxyPassReverse Direktive wird der Webserver angegeben, der unter subdomain.domain.de erreichbar sein soll. Wichtig zu wissen ist hierbei, dass man mehrere dieser VirtualHost Konfigurationen gleichzeitig einsetzen kann. An dem Domainnamen wird festgemacht, welche Konfiguration für eine Weiterleitung genutzt wird. Wenn ich nun also subdomain2.domain.de im Webbrowser aufrufen würde, wurde der Reverseproxy in ein Timeout laufen, da es hierzu noch keine Konfiguration gibt. Und genau das wollen wir. Denn nur deshalb kann ein Webserver (in diesem Fall ReverseProxy) mehrere Seiten über eine IP bedienen.

<VirtualHost *:80>
    ServerName subdomain.domain.de
    ProxyPreserveHost On

    ProxyPass / http://172.31.10.195/
    ProxyPassReverse / http://172.31.10.195/
</VirtualHost>
<VirtualHost *:443>
    SSLEngine On
    SSLProxyEngine On

    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    ServerName subdomain.domain.de
    ProxyPreserveHost On

    #SSLCACertificateFile /etc/apache2/ssl/Intermediate_CA_Bundle.crt
    SSLCertificateFile /etc/apache2/ssl/cert.crt
    SSLCertificateKeyFile /etc/apache2/ssl/cert.key

    ProxyPass / https://172.31.10.195/
    ProxyPassReverse / https://172.31.10.195/
</VirtualHost>
a2enconf revproxy
systemctl reload apache2

Über das auskommentierte SSLCACertificateFile kann man Intermediate Keys einbinden. Sofern das Intermediate Key also nicht bereits im SSLCertificateFile enthalten ist, sollte man das Zertifikat separat angeben.

Damit ist der Reverseproxy für den ersten Webserver konfiguriert. Weitere Konfigurationen für weitere Webserver können nun hinzugefügt werden.

Websockets

Soll der Reverseproxy auch Websockets unterstützen, muss die extra konfiguriert werden.

https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

Erstmal aktivieren wir die nötigen Module

sudo a2enmod rewrite
sudo a2enmod proxy_wstunnel

Dann die VirtualHost-Konfiguration anpasssen. Aus der Verlinkung oben:

Proxying both HTTP and websockets at the same time, where the websockets URL’s are not websocket-only or not known in advance can be done by using the RewriteRule directive to configure the websockets proxying:

https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html
ProxyPass / http://example.com:9080/
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://example.com:9080/$1" [P,L]

Loggen von Remote IP’s auf den Hosts hinter dem ReverseProxy

Apache

Step 1 – Konfiguration von mod_remoteip

Auf dem Reverseproxy selbst werden die eingehenden Verbindungen mit der richtigen RemoteIP geloggt. Auf den Servern hinter dem Remoteproxy wird in der Standardkonfiguration die IP das Reverseproxy geloggt. Wer also auch auf den Servern hinter dem Reverseproxy die RemoteIP des Clients sehen will, muss das Loggen von RemoteIP’s konfigurieren. Das geht bei Apache mit mod_remote. Der Reversoproxy bringt die dafür nötigen über mod_proxy mit ein:

https://httpd.apache.org/docs/current/mod/mod_proxy.html#x-headers

Wir erstellen hierzu auf den Hosts hinter dem ReverseProxy eine weitere Konfig, die einen X-Forwarded-For Header für alle VirtualHosts implementiert. Man kann die Konfiguration auch pro VirtualHost konfigurieren. Die globale Konfiguration hält die VirtualHosts aber kleiner und gilt auch für neue VirtualHosts.

Hierfür wird das Modul remoteip beötigt:

sudo a2enmod remoteip

sudo vi /etc/apache2/conf-available/remoteip.conf

Folgenden Inhalt einfügen:

RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 127.0.0.1

Konfig aktivieren und Apache neu laden:

a2enconf remoteip

Step 2 – Apache Logformat anpassen

Nun muss noch das Logformat in der apache2.conf angepasst werden. Wir ersetzen %h mit %a, behalten sonst aber die Originalkonfiguration.

https://httpd.apache.org/docs/2.4/mod/mod_log_config.html#formats

sudo vi /etc/apache2/apache2.conf

LogFormat "%v:%p %a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%a %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

Dann den Apache neu starten und fertig:

systemctl reload apache2

Nginx

Nginx unterstützt den Kram nativ. Man muss nur das Logformat unter /etc/nginx/nginx.conf anpassen.

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

Wenn man die RemoteIP vorne im Log haben will:

    log_format  main  '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent"';

    access_log  /var/log/nginx/access.log  main;

Achtung: wenn eine VirtualHost-Konfiguration auf dem Nginx einen Eintrag für ein eigenes access log enthält, muss diesem auch das main hintenangestellt werden.

Mod_security

mod_security befindet sich gerade in einer Transitionsphase. Es war früher nur als Apache Modul erhältlich, wurde aber in einen plattformunabhängigen Kern umgewandelt und kann nun auch für Nginx oder den ISS eingesetzt werden. Für jede Plattform gibt es dann einen zusätzlichen Connector, der die Plattforminterna abbildet. Das mod_security Team empfiehlt für den Einsatz im Apache aber noch immer das Paket libapache2-mod-security2 (Stand 07.12.2021), siehe Link zu ModSecurity-apache Connector.

https://github.com/SpiderLabs/ModSecurity

https://github.com/SpiderLabs/ModSecurity-nginx

https://github.com/SpiderLabs/ModSecurity-apache

https://github.com/coreruleset/coreruleset

https://wiki.ubuntuusers.de/Archiv/Apache/mod_security/

https://github.com/SpiderLabs/ModSecurity/wiki

Installation

Wir konfigurieren den Apache und installieren daher libapache2-mod-security2, was zusätzlich auch das Core Ruleset installiert (modsecurity-crs):

sudo apt install libapache2-mod-security2
sudo systemctl restart apache2

Nun aktivieren wir noch die empfohlene Konfiguration von ModSecurity:

cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

ModSecurity läuft nun im Detection Mode. Es wird also noch keine Inhalte auf Basis der Regeln implementieren. Um das zu ändern Setzen wir in /etc/modsecurity/modsecurity.conf die Direktive:

SecRuleEngine On #DetectionOnly

Das wars auch schon. Ob ModSecurity ordentlich gestartet ist kann man über das error.log einsehen. Da steht dann sowas drin wie:

ModSecurity for Apache/2.9.3 (http://www.modsecurity.org/) configured.

Pfade und Zusammenhänge

Die Installation unter Debian teilt sich in ein paar Teilbereiche auf.

Installationspfade und Hauptkonfigurationsdateien

Apche ModSecurity Modulkonfiguration

/etc/apache2/mods-available/security2.conf

Über die Apache ModSecurity Modulkonfiguration wird die modsecurity.conf und die owasp-crs.load eingebunden

ModSecurity: /etc/modsecurity/modsecurity.conf

Konfigurationsdatei von Modsecurity

Core Ruleset: /usr/share/modsecurity-crs/owasp-crs.load

Die Datei lädt die Core Ruleset Regeln. Diese teilen sich in unterschiedliche Dateien auf. Konkret steht in dieser Datei folgendes:

Include /etc/modsecurity/crs/crs-setup.conf
IncludeOptional /etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
Include /usr/share/modsecurity-crs/rules/*.conf
IncludeOptional /etc/modsecurity/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

Die crs-setup.conf sollte man sich durchlesen und ggf. Anpasungen vornehmen.

Test

Kuerzer Test, ob die Regeln greifen:

https://www.domain.com/aphpfilethatdonotexist.php?something=../../etc

Der Zugriff wird mit HTTP 403 Forbidden verweigert und unter /var/log/apache2/error.log sollte nun der Grund für die Verweigerung stehen.

Beispiele

Für die angegebene Webseite die Regel 930120 einschränken, so dass kein XML geparst wird:

SecRule SERVER_NAME "sub.domain.com" "phase:2,id:12005,nolog,allow,ctl:ruleRemoveTargetById=930120;XML:/*"

Für die angegebene Webseite die Regel 930120 einschränken, so dass das Argument (ARG) xr nicht geparst wird. Dieses Argument könnte auch ein Argument auf der ersten Hierachrieebene von einem JSON-Anteil sein. Die zweite Hierarchieebene erreicht man über eine Punktnoation (z.B. xr.windows.width).

SecRule SERVER_NAME "wikitest.fps-law.de" "phase:2,id:12005,nolog,allow,ctl:ruleRemoveTargetById=930120;ARGS:xr"

Engine für einen bestimmten URI-Anteil ausschalten

SecRule REQUEST_URI "@beginsWith /rest/api/user/watch" \
        "phase:1,\
        id:12003,\
        nolog,\
        allow,\
        ctl:ruleEngine=off"

Regeln für einen bestimmten Webseitenanteil ausschalten

SecRule REQUEST_URI "@beginsWith /pages/doeditpage.action" \
        "phase:1,\
        id:12002,\
        nolog,\
        allow,\
        ctl:ruleRemoveById=941100,\
        ctl:ruleRemoveById=941160"

Verschachteln von Regeln

SecRule REQUEST_METHOD "@streq PUT" \
    "id:9003105,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.0',\
    chain"
    SecRule REQUEST_FILENAME "@contains /remote.php/webdav" \
        "t:none,\
        ctl:ruleRemoveById=920000-920999,\
        ctl:ruleRemoveById=932000-932999,\
        ctl:ruleRemoveById=921150,\
        ctl:ruleRemoveById=930110,\
        ctl:ruleRemoveById=930120"

Wissenswertes

ARG und ARG_NAMES werden auf den GET und POST Requests gebildet.

http://server.invalid/test.php?pretty_arg=test123&ugly_arg=345test

ARGS_NAMES = "pretty_arg","ugly_arg"
ARGS = "pretty_arg:test123","ugly_arg:345test" 

Man kann diese Werte in Regeln verwenden, z.B. um Anteile eines Requests von der Prüfung in einer Regel auszuschließen.

SecRule REQUEST_FILENAME "@streq /path/to/file.php" "phase:1,id:2001,t:none,nolog,pass,ctl:ruleRemoveTargetById=959072;ARGS:ugly_arg"

Die ModSecurity Direktiven sind gleichzeitig Apache Direktiven. Man kann diese also in einem VirtualHost-Eintrag verwenden. Nach meinen Erkenntnissen aber nur die Regeln für Phase 1 Checks.

https://malware.expert/modsecurity/processing-phases-modsecurity/

Die Sicherheitregeln kann man in eigene Konfigs packen oder in die dafür vorgesehenen Dateien

/etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
/etc/modsecurity/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf

Eine Sicherheitsregel muss immer eine ID erhalten, die man aus einem Pool mehr oder weniger frei wählen kann.

Apache Config als Referenz

Hier eine Beispielkonfiguration mit allerhand modsecurity-Regeln als kleine Referenz. Die Konfiguration stammt von einer Confluence onPremise Installation. Der Domänname ist fiktiv und hat nichts mit evtl. real existierenden Domänen zu tun. Wenn Teilbereiche der Website durch modsecurity geblockt werden, stehen die Details dazu im Error-Log des Servers (tail -f /var/log/apache2/error.log -n200).

<VirtualHost *:80>
    ServerName wiki.domain.de
    ProxyPreserveHost On

    Redirect permanent / https://wiki.domain.de/

#    RewriteEngine on
#    RewriteCond %{SERVER_NAME} =wiki.domain.de [OR]
#    RewriteCond %{SERVER_NAME} =wiki.domain.de
#    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]

</VirtualHost>
<VirtualHost *:443>
    ServerName wiki.domain.de
    ProxyRequests Off
    ProxyVia Off
    ProxyPreserveHost On

    SSLEngine On
    SSLProxyEngine On

    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    #SSLCACertificateFile /etc/apache2/ssl/Intermediate_CA_Bundle.crt
    SSLCertificateFile /etc/apache2/ssl/domain.de.crt
    SSLCertificateKeyFile /etc/apache2/ssl/domain.de.key

    ProxyPass / https://172.32.0.95/ # Das ist die IP des eigentlichen Webservers
    ProxyPassReverse / https://172.32.0.95/

    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/?(.*) "wss://172.32.0.95/$1" [P,L]

    <IfModule mod_security2.c>
        SecRuleEngine On

        #### Editor laden 1 ####
        SecRule REQUEST_URI "@beginsWith /rest/tinymce/1/drafts" \
                        "phase:1,\
                        id:13001,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=941100,\
                        ctl:ruleRemoveById=941160"

        #### Editor laden 2 ####
        SecRule REQUEST_URI "@beginsWith /pages/doeditpage.action" \
                        "phase:1,\
                        id:13002,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=941100,\
                        ctl:ruleRemoveById=941160"

        #### Editor speichern 1 ####
        SecRule REQUEST_URI "@beginsWith /rest/api/content" \
                        "phase:1,\
                        id:13003,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=941100,\
                        ctl:ruleRemoveById=941160"

        #### Beobachten-Feature ####
        SecRule REQUEST_URI "@beginsWith /rest/api/user/watch" \
                        "phase:1,\
                        id:13004,\
                        nolog,\
                        allow,\
                        ctl:ruleEngine=off"
        #        ctl:ruleRemoveById=200002"

        #### Favorit-Feature, disable Engine so Logs don't generate JSON Error Messages ####
        SecRule REQUEST_URI "@beginsWith /rest/experimental/relation/user/current/favourite" \
                        "phase:1,\
                        id:13011,\
                        nolog,\
                        allow,\
                        ctl:ruleEngine=off"

        #### Der JSON-Baum xr beinhaltet zu ladende Module. ModSec erkennt dort einen Anteil .profile (definiert in der Regeldatei lfi-os-files.data) als Dateisystemattacke ####
        SecRule REQUEST_URI "@beginsWith /rest/webResources" "phase:1,id:13021,nolog,allow,ctl:ruleRemoveTargetById=930120;ARGS:xr"
        SecRule REQUEST_FILENAME "@contains .profile" "phase:1,id:13022,nolog,allow,ctl:ruleRemoveTargetById=930120;ARGS:xr"

        #### Makros im Editor einfügen - [id "941160"] [msg "NoScript XSS InjectionChecker: HTML Injection"] ####
        SecRule REQUEST_URI "@beginsWith /rest/tinymce/1/macro" "phase:1,id:13023,nolog,allow,ctl:ruleRemoveTargetById=941160;ARGS:macroHTML"

        #### Backend Konfiguration ####
        SecRule REQUEST_URI "@beginsWith /admin" \
                        "phase:1,\
                        id:13024,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=932130,\
                        ctl:ruleRemoveById=941100,\
                        ctl:ruleRemoveById=941160

        #### Analytics ####
        SecRule REQUEST_URI "@beginsWith /rest/analytics" \
                        "phase:1,\
                        id:13025,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=921130

        #### User Suche / individuelle Benutzerliste ####

        SecRule REQUEST_URI "@beginsWith /rest/cup/1.0/search/users/by/cql" \
                        "phase:1,\
                        id:13026,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=942100

        #### App Updates ####
        SecRule REQUEST_URI "@beginsWith /rest/plugins/1.0/" \
                        "phase:1,\
                        id:13031,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=920420
        #### Suche ####
        SecRule REQUEST_URI "@beginsWith /rest/api/search" \
                        "phase:1,\
                        id:13032,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=942100
        SecRule REQUEST_URI "@beginsWith /dosearchsite.action" \
                        "phase:1,\
                        id:13033,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=942100

        #### Misc ####
        SecRule REQUEST_URI "@beginsWith /rest/masterdetail/1.0/detailssummary/lines" \
                        "phase:1,\
                        id:13034,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=980130

        SecRule REQUEST_URI "@contains /comment" \
                        "phase:1,\
                        id:13035,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=941160
        #### Uploads ####

        SecRule REQUEST_URI "@beginsWith /rest/synchrony/1.0/content" \
                        "phase:1,\
                        id:13036,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=200002


        SecRule REQUEST_URI "@beginsWith /plugins/drag-and-drop/upload.action" \
                        "phase:1,\
                        id:13037,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=921110

        SecRule REQUEST_URI "@beginsWith /pages/doattachfile.action" \
                        "phase:1,\
                        id:13038,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=200004
        #### Misc 2 ####
        SecRule REQUEST_URI "@beginsWith /rest/cql/expressions" \
                        "phase:1,\
                        id:13039,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=942100

        SecRule REQUEST_URI "@beginsWith /rest/searchv3/1.0/cqlSearch" \
                        "phase:1,\
                        id:13040,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=942100
        SecRule REQUEST_URI "@beginsWith /pages/rendercontent.action" \
                        "phase:1,\
                        id:13041,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=932115,\
                        ctl:ruleRemoveById=941100,\
                        ctl:ruleRemoveById=941160
        SecRule REQUEST_URI "@beginsWith /rest/create-dialog" \
                        "phase:1,\
                        id:13042,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=920420
        SecRule REQUEST_URI "@beginsWith /pages/templates2/doeditpagetemplate.action" \
                        "phase:1,\
                        id:13043,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=941160,\
                        ctl:ruleRemoveById=941100
        SecRule REQUEST_URI "@beginsWith /pages/templates2/docreatepagetemplate.action" \
                        "phase:1,\
                        id:13044,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=941160,\
                        ctl:ruleRemoveById=941100

        # Profil-Fotos hochladen
        SecRule REQUEST_URI "@beginsWith /rest/cup/1.0/profile" \
                        "phase:1,\
                        id:13045,\
                        nolog,\
                        allow,\
                        ctl:ruleRemoveById=941130,\
                        ctl:ruleRemoveById=941170

        # Zugriff von extern sperren
        SecRule REMOTE_ADDR "!@ipMatchF /etc/apache2/ipaccesslist.txt" \
                        "phase:1,\
                        id:13046,\
                        nolog,\
                        deny

    </IfModule>

</VirtualHost>