Apache httpd

Siehe auch

Der Apache HTTP-Server der Apache Software Foundation ist einer der meistgenutzten Webserver im Internet. Ein Webserver ist ein Daemon, der per HTTP bzw. HTTPS kommuniziert. HTTP ist ein Klartext-Protokoll (Standard-Port: 80/tcp), HTTPS ist die TLS/SSL-verschlüsselte Variante (Standard-Port: 443/tcp).

HTTP ist ein Request-Response-Verfahren, bei dem ein Client die Verbindung zum Server aufnimmt und beispielsweise per GET-Request um die Auslieferung einer Ressource (z.B. einer HTML-Datei) bittet. Der Server antwortet mit einem HTTP-Statuscode (im Erfolgsfall mit HTTP/1.1 200 OK), einigen Protokolldaten (Header) wie dem Typ und der Länge der Antwort und dem eigentlichen Inhalt.

CentOS 8 kommt mit Apache 2.4.37. CentOS 7 wird mit der Apache-Version 2.4.6 geliefert, was diverse Neuerungen seit CentOS 6 mit Apache 2.2.15 mit sich bringt:

  • service httpd graceful wird zu apachectl graceful

  • Viele Apache-Standardeinstellungen sind eincompiliert, die httpd.conf ist dementsprechend kürzer.

  • Die Konfigurationsdateien unter /etc/httpd wurden modularisiert sowie die Ladereihenfolge verändert: zuerst werden alle Module aus dem Verzeichnis /etc/httpd/conf.modules.d geladen, dann wird der Apache Core-Service per /etc/httpd/conf/httpd.conf konfiguriert - und erst danach werden weitere Konfigurationsanweisungen aus /etc/httpd/conf.d/* abgearbeitet. In letzterem Verzeichnis legt man daher eigene Konfigurationsdateien ab und folgt dabei am besten dem vorhandenen Bennungsschema, welches eine fixe Abarbeitungsreihenfolge ermöglicht.

  • Die Syntax der Konfigurationsdateien hat sich teilweise geändert. So wurde u.a. Order deny,allow durch Require ...​ ersetzt.

Eine Migration ist demnach mit Aufwand verbunden, hier gilt es die Release Notes und den Migrationsleitfaden zu studieren.

Direktiven

  • IfModule
    <IfModule filename> (mod_rewrite.c) oder <IfModule identifier> (rewrite_module).

vHosts

Einfacher vHost

/etc/httpd/conf.d/myvhosts.conf
<VirtualHost *:80>
    ServerName www.linuxfabrik.ch
    ServerAdmin webmaster@linuxfabrik.ch
    ErrorLog logs/error.log
    CustomLog logs/access.log combined
    DocumentRoot /var/www/html
    <Directory /var/www/html>
        Require all granted
    </Directory>
</VirtualHost>

Werden Optionen wie DocumentRoot, ErrorLog usw. weggelassen, werden sie aus der Hauptkonfiguration vererbt.

Für einen TLS-abgesicherten virtuellen Host wird benötigt:

  • der Apache mit mod_ssl

  • das Server-Zertifikat (im Beispiel als /etc/pki/tls/certs/mycrt.crt abgelegt)

  • der Schlüssel zum Zertifikat (/etc/pki/tls/private/mycrt.key)

  • das CA-Zertifikat, welches die Signaturprüfung des privaten Zertifikates ermöglicht (im Beispiel handelt es sich um ein CA-Chain-Zertifikat, nicht um ein einfaches CA-Zertifikat - /etc/pki/tls/certs/myca.crt)

yum -y install mod_ssl
chmod 0400 /etc/pki/tls/private/mycrt.key
/etc/httpd/conf.d/myvhosts.conf
<VirtualHost *:443>
    ServerName www.linuxfabrik.ch
    ServerAdmin webmaster@linuxfabrik.ch
    ErrorLog logs/error.log
    CustomLog logs/access.log combined
    DocumentRoot /var/www/html
    <Directory /var/www/html>
        Require all granted
    </Directory>
    SSLEngine on
    SSLCertificateFile /etc/pki/tls/certs/mycrt.crt
    SSLCertificateKeyFile /etc/pki/tls/private/mycrt.key
    SSLCertificateChainFile /etc/pki/tls/certs/myca.crt
</VirtualHost>

Falls mehrere virtuelle Hosts auf dem gleichen Port konfiguriert werden und für eine Client-Anfrage kein passender Host gefunden wird, versucht Apache, den angeforderten Inhalt über den ersten konfigurierten virtuellen Host auszuliefern. Welcher virtuelle Host nun wirklich der Standard-Host ist, und wer auf welchen Namen auf welcher IP-Adresse hört, lässt sich so anzeigen:

httpd -t -D DUMP_VHOSTS

HTTP

Request Headers vs. Response Headers

  • Ein Response-Header geht als Antwort zurück an den Browser:
    Header set server: "nginx"
  • Ein Request-Header geht an (andere) Webserver, z.B. bei Apache als ReverseProxy an die Backend-Applikation:
    RequestHeader set Authentication-Context-Policy "internet"

HTTP/2

Global oder im VirtualHost HTTP/2 aktivieren - ab Apache 2.4.17 (also CentOS 8 oder höher):

# support HTTP/2 for a server with HTTP, plus http/1.1:
Protocols h2c http/1.1

# support HTTP/2 for a server with TLS, plus http/1.1:
Protocols h2 http/1.1

# it is safe to specify protocols that are unavailable/disabled, so:
Protocols h2 h2c http/1.1

Letzere Angabe resultiert in einem upgrade: h2,h2c Response-Header.

HTTPS ist eigentlich Voraussetzung für HTTP/2, weswegen das Modul auch per mod_ssl does not seem to be enabled warnt, falls mod_ssl nicht aktiv ist.

Test, ob HTTP/2 angeboten wird:

curl --http2 --head --silent https://myserver
# HTTP/2.0 200

Module

mod_auth_openidc (auth_openidc_module; Keycloak, OAuth)

Apache kann als Reverse Proxy mit OpenID Connect (und separat zu installierendem Modul) eine Web-Applikation per Keycloak absichern.

Apache-Konfiguration: Keycloak ist im Beispiel über http://192.168.122.235:8080/ erreichbar, die Applikation unter anderem auf http://192.168.122.235/test.php (Keycloak-UUID 3323f2c6-5389-4bc3-9a25-a8d8ae64c6d4):

Keycloak-Seite

Neuer Client „Webapp“ mit „openid-connect“.

  • Clients > „Webapp“ > Settings

    • Client ID: Webapp

    • Name: Webapp (wird im Self-Service-Portal unter „Applications“ verwendet)

    • Description: Any descriptive text (wird im Self-Service-Portal unter „Applications“ verwendet)

    • Client Protocol: openid-connect

    • Access Type: confidential

    • Valid Redirect URIs: http://192.168.122.235/test.php*

    • Base URL: http://192.168.122.235/test.php (wird im Self-Service-Portal unter „Applications“ verwendet)

Falls Rollenangaben genutzt werden sollen, gehören diese in die Userinfo, nicht ins Aceess- oder Identity-Token:

  • Clients > „Webapp“ > Roles

    • Name: roles

    • Mapper Type: User Realm Role

    • Token Claim Name: roles

    • Claim JSON Type: String

    • Add to userinfo: ON (Rest OFF)

Apache-Seite

Apache konfigurieren:

yum -y install mod_auth_openidc
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule auth_openidc_module modules/mod_auth_openidc.so

Siehe dann auch /usr/share/doc/mod_auth_openidc-*/README.md.

vhost.conf
<IfModule auth_openidc_module>
    OIDCClientID example
    OIDCClientSecret 3323f2c6-5389-4bc3-9a25-a8d8ae64c6d4

    # just use any password - Passphrase used for AES crypto on cookies and state
    OIDCCryptoPassphrase saKbs7KKLDJkkPg0vsn4I7NPsdntKHdk

    OIDCProviderMetadataURL http://192.168.122.235:8080/auth/realms/example/.well-known/openid-configuration

    # See https://github.com/Reposoft/openidc-keycloak-test/issues/7
    OIDCProviderTokenEndpointAuth client_secret_basic

    OIDCRedirectURI http://192.168.122.235/*
    OIDCRemoteUserClaim email
    OIDCScope "openid email"
</IfModule>

# just a valid user
<Location />
   AuthType openid-connect
   Require valid-user
</Location>

# use this if role mebership must be met
<Location />
    AuthType openid-connect
    Require claim roles:oem
</Location>

SELinux: Apache Zugriff auf Keycloak erlauben:

setsebool -P httpd_can_network_connect on

Siehe auch

mod_evasive (evasive20_module)

Falls kein Schutz vor DDoS Attacken vorhanden ist, kann das mod_evasive Modul von Apache installiert werden. Dieses Modul erkennt Angriffe über eine IP-Adresse und sperrt die Angreifer-IP für einen definierten Zeitraum. Darüber hinaus kann das Modul den Administrator per E-Mail über einen potentiellen Angriff informieren.

Es gibt aber ein paar Einschränkungen:

  • Wohl nur HTTP, kein HTTPS

  • Probleme hinter Reverse Proxy (X-Forwarded-For header value setzen, sonst wird der Reverse Proxy geblockt)

  • Die zum Blockieren verwendeten Statistiken werden in jedem Child-Prozess gespeichert. Wenn man Prefork MPM verwendet und MaxClients auf 50 gesetzt hat, werden die Verbindungen zu jedem dieser 50 Clients unabhängig voneinander verfolgt.

  • Darüber hinaus wird bei erreichen der MaxRequestsPerChild der Child-Prozess gekillt, inkl. Statistiken. In einigen Fällen ist mod_evasive daher einfach nicht effektiv.

LoadModule evasive20_module modules/mod_evasive24.so

<IfModule evasive20_module>
    DOSHashTableSize    8192
    DOSWhitelist        1.2.3.4
    DOSBlockingPeriod   10

    DOSPageInterval     1
    DOSPageCount        20

    DOSSiteInterval     1
    DOSSiteCount        128

    DOSEmailNotify      root
</IfModule>

Siehe auch https://github.com/jzdziarski/mod_evasive

mod_ftp

Siehe https://httpd.apache.org/mod_ftp/

mod_geoip (GeoIP-Blocking, deprecated)

Das von MaxMind stammende mod_geoip für Apache 2 ist uralt und ungepflegt; der Support für das Modul endet März 2022, die vom Modul verwendeten MaxMind-Datenbanken sind ausdrücklich als Legacy gekennzeichnet (und von MaxMind nicht mehr herunterladbar).

Doku und Source: https://github.com/maxmind/geoip-api-mod_geoip2

# from the EPEL repo:
yum -y install mod_geoip

Konfiguration entweder Server-weit, oder in einem vHost:

<IfModule mod_geoip.c>
    GeoIPEnable On
    GeoIPDBFile /usr/share/GeoIP/GeoIP.dat

    GeoIPEnableUTF8 On
    GeoIPOutput Env

    # on a vHost you need this:
    GeoIPScanProxyHeaders On

    # on a ReverseProxy, you need this:
    GeoIPScanProxyHeaders On

    # Method 1: Allow all, but block some specific countries
    SetEnvIf GEOIP_COUNTRY_CODE UA BlockCountry
    SetEnvIf GEOIP_COUNTRY_CODE VN BlockCountry

    # within a <Proxy>, <Directory>, <Location> or <Files> container:
    <RequireAll>
        Require all granted
        Require not env BlockCountry
    </RequireAll>


    # Method 2: Deny all, but allow some specific countries
    SetEnvIf GEOIP_COUNTRY_CODE DE AllowCountry
    SetEnvIf GEOIP_COUNTRY_CODE CH AllowCountry

    # within a <Proxy>, <Directory>, <Location> or <Files> container:
    <RequireAny>
        Require env AllowCountry
    </RequireAny>

    # list of IP's in an external file, containing lines like
    # Require ip 10.1
    Include /etc/file-with-IP-list.conf
</IfModule>

mod_maxminddb (GeoIP-Blocking)

Ebenfalls von MaxMind: mod_maxminddb ist der Nachfolger des alten mod_geoip-Moduls.

Voraussetzungen schaffen:

yum -y install make gcc httpd-devel redhat-rpm-config

Compilierung der MaxMind Bibliothek:

# https://github.com/maxmind/libmaxminddb/releases
VER=1.8.0
wget https://github.com/maxmind/libmaxminddb/releases/download/$VER/libmaxminddb-$VER.tar.gz
tar xzf libmaxminddb-$VER.tar.gz
cd libmaxminddb-$VER

./configure
make
make check
make install

# Configure Dynamic Linker Run Time Bindings:
echo /usr/local/lib  >> /etc/ld.so.conf.d/local.conf
ldconfig

Compilierung des MaxMind Apache-Moduls:

# https://github.com/maxmind/mod_maxminddb/releases
VER=1.2.0
wget https://github.com/maxmind/mod_maxminddb/releases/download/$VER/mod_maxminddb-$VER.tar.gz
tar xzf mod_maxminddb-$VER.tar.gz
cd mod_maxminddb-$VER
./configure
make install

Das Modul findet sich danach in /usr/lib64/httpd/modules/mod_maxminddb.so. Das make-Script ändert unter Umständen die conf/httpd.conf und fügt LoadModule maxminddb_module /usr/lib64/httpd/modules/mod_maxminddb.so ein, sofern sie noch dem Standard entspricht. Wer sonst die Meldung apxs:Error: Activation failed for custom /etc/httpd/conf/httpd.conf file.. und apxs:Error: At least one `LoadModule' directive already has to exist.. erhält, sollte die LoadModule von Hand einfügen und make install nochmal laufen lassen.

Anschliessend

GeoIP2-Datenbanken herunterladen (für das Beispiel unten genügt die GeoIP2-Country-Datenbank).

Konfiguration des Apache (siehe https://github.com/maxmind/mod_maxminddb):

<IfModule maxminddb_module>
    MaxMindDBEnable On
    MaxMindDBFile COUNTRY_DB /usr/share/GeoIP/GeoLite2-Country.mmdb
    MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code


    # Method 1: Allow all, but block some specific countries
    SetEnvIf MM_COUNTRY_CODE UA BlockCountry
    SetEnvIf MM_COUNTRY_CODE VI BlockCountry

    # within a <Proxy>, <Directory>, <Location> or <Files> container:
    <RequireAll>
        Require all granted
        Require not env BlockCountry
    </RequireAll>


    # Method 2: Deny all, but allow some specific countries
    SetEnvIf MM_COUNTRY_CODE DE AllowCountry
    SetEnvIf MM_COUNTRY_CODE CH AllowCountry

    # within a <Proxy>, <Directory>, <Location> or <Files> container:
    <RequireAny>
        Require env AllowCountry
        # list of IP's in an external file, containing lines like
        # Require ip 10.1
        Include /etc/GeoIP-Whitelist.conf
    </RequireAny>

</IfModule>

Regelmässiger Update der GeoIP2-Datenbanken von maxmind per Shell-Script:

#!/usr/bin/env bash

MM_LIC=my-maxmind-lic
MM_DB=GeoLite2-Country

cd /tmp
wget --quiet "https://download.maxmind.com/app/geoip_download?edition_id=$MM_DB&suffix=tar.gz&license_key=$MM_LIC" -O $MM_DB.tar.gz
tar xzf $MM_DB.tar.gz
\cp GeoLite2-Country_*/GeoLite2-Country.mmdb /usr/share/GeoIP/
rm -rf /tmp/GeoLite2-Country*

mod_proxy_balancer (proxy_balancer_module)

Es gibt vier Methoden, die der Load Balancer verwenden kann:

  1. mod_lbmethod_bybusyness https://httpd.apache.org/docs/2.4/de/mod/mod_lbmethod_bybusyness.html

  2. mod_lbmethod_byrequests https://httpd.apache.org/docs/2.4/de/mod/mod_lbmethod_byrequests.html

  3. mod_lbmethod_bytraffic https://httpd.apache.org/docs/2.4/de/mod/mod_lbmethod_bytraffic.html

  4. mod_lbmethod_heartbeat https://httpd.apache.org/docs/2.4/de/mod/mod_lbmethod_heartbeat.html

Beispiel-Konfiguration für „byrequests“ mit Sticky Sessions:

<VirtualHost 192.168.2.41:8080>
    ServerName loadbalancer

    Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED

    ProxyErrorOverride On
    ProxyPreserveHost On
    ProxyRequests Off
    ProxyTimeout 30
    ProxyVia Off

    ProxyPass / balancer://cluster/
    ProxyPassReverse / balancer://cluster/
    <Proxy balancer://cluster>
            BalancerMember http://192.168.2.201:8080 route=1
            BalancerMember http://192.168.2.202:8080 route=2
            ProxySet lbmethod=byrequests
            ProxySet stickysession=ROUTEID
    </Proxy>
</VirtualHost>

Siehe https://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html

Wichtig

ProxyPass-Direktiven führen ein automatisches URL-Encoding durch. Werden ProxyPass-Direktiven der Flexibilität wegen durch RewriteRules ersetzt, werden URIs mit Backreferences aber unter Umständen dekodiert. Siehe dazu auch unseren Blog-Beitrag.

mod_qos (qos_module)

Apache mod_qos kann installiert werden um unter anderem gegen Slowloris-Angriffe zu schützen (bei diesen Angriffen werden möglichst viele Verbindungen zum Server aufgebaut, aber nicht geschlossen).

Achtung: mod_qos sollte mit dem ‚Worker‘-MPM verwendet werden, nicht mit dem ‚Prefork‘-MPM. Wird das geändert, ist das Standard PHP-Modul allerdings nicht mehr verwendbar, da es nicht thread-safe compiliert wurde.

# from EPEL repository
yum -y install mod_qos

Konfigurationsbeispiel:

/etc/httpd/conf.modules.d/00-mpm.conf
# prefork MPM: Implements a non-threaded, pre-forking web server
# See: http://httpd.apache.org/docs/2.4/mod/prefork.html
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so

# worker MPM: Multi-Processing Module implementing a hybrid
# multi-threaded multi-process web server
# See: http://httpd.apache.org/docs/2.4/mod/worker.html
LoadModule mpm_worker_module modules/mod_mpm_worker.so
/etc/httpd/conf.d/my_vhost.conf
BrowserMatch "(curl|wget)" QS_Cond=tools

# Defines the number of concurrent requests
# for the specified request pattern (path and query)
# The rule with the lowest number of allowed concurrent connections
# has the highest priority if multiple expressions match the request
QS_LocRequestLimitMatch       "^.*$"   200
QS_LocRequestLimitMatch       \.iso    100
QS_CondLocRequestLimitMatch   \.iso    5    tools

# Throttles the download bandwidth to the defined kbytes per second
# for the specified request pattern (path and query)
QS_LocKBytesPerSecLimitMatch  \.iso   640

Status-Seite (wird maschinenlesbar, wenn ein ?auto angehängt wird):

/etc/httpd/conf/httpd.conf
<IfModule qos_module>
    <Location /qos-status>
        SetHandler qos-viewer
        Require ip ::1
        Require ip 127.0.0.1
    </Location>
</IfModule>

Siehe http://mod-qos.sourceforge.net/index.html

mod_security2 (security2_module)

Siehe auch

  • Vulture Project

  • Roxy-WI

  • Janusec

Ursprünglich von TrustWave SpiderLabs entwickelt. Die Doku auf https://coreruleset.org/documentation/ ist nicht ganz aktuell, hier findet man ausführlichere Informationen:

yum -y install mod_security

Konfigurationsdateien liegen in /etc/httpd/modsecurity.d. Wir sorgen in der Konfiguration dafür, dass diese nicht angewendet und mit eigenen Regeln überschrieben werden.

Das OWASP ModSecurity Core Rule Set (CRS) von OWASP ziehen und Regelwerk in /etc/httpd/conf.d/owasp.conf bauen:

# https://github.com/coreruleset/coreruleset/releases
VER=3.3.2
cd /etc/httpd/modsecurity.d
wget https://github.com/coreruleset/coreruleset/archive/v$VER.tar.gz
tar xvzf v$VER.tar.gz
ln -s /etc/httpd/modsecurity.d/coreruleset-$VER /etc/httpd/modsecurity.d/crs
cp crs/crs-setup.conf.example crs/crs-setup.conf
rm -f v$VER.tar.gz

Konfiguration für einen Apache Reverse Proxy auf Red Hat-kompatiblen Systemen:

/etc/httpd/conf/httpd.conf
<IfModule security2_module>
    SecPcreMatchLimit             100000
    SecPcreMatchLimitRecursion    100000
    SecDataDir                    /tmp/
</IfModule>
/etc/httpd/conf.d/vhost.conf
<IfModule security2_module>

    LogFormat "%h %{GEOIP_COUNTRY_CODE}e %u [%{%Y-%m-%d %H:%M:%S}t.%{usec_frac}t] \"%r\" %>s %b \
    \"%{Referer}i\" \"%{User-Agent}i\" \"%{Content-Type}i\" %{remote}p %v %A %p %R \
    %{BALANCER_WORKER_ROUTE}e %X \"%{cookie}n\" %{UNIQUE_ID}e %{SSL_PROTOCOL}x %{SSL_CIPHER}x \
    %I %O %{ratio}n%% %D %{ModSecTimeIn}e %{ApplicationTime}e %{ModSecTimeOut}e \
    %{ModSecAnomalyScoreInPLs}e %{ModSecAnomalyScoreOutPLs}e \
    %{ModSecAnomalyScoreIn}e %{ModSecAnomalyScoreOut}e" extended

    LogFormat "[%{%Y-%m-%d %H:%M:%S}t.%{usec_frac}t] %{UNIQUE_ID}e %D \
    PerfModSecInbound: %{TX.perf_modsecinbound}M \
    PerfAppl: %{TX.perf_application}M \
    PerfModSecOutbound: %{TX.perf_modsecoutbound}M \
    TS-Phase1: %{TX.ModSecTimestamp1start}M-%{TX.ModSecTimestamp1end}M \
    TS-Phase2: %{TX.ModSecTimestamp2start}M-%{TX.ModSecTimestamp2end}M \
    TS-Phase3: %{TX.ModSecTimestamp3start}M-%{TX.ModSecTimestamp3end}M \
    TS-Phase4: %{TX.ModSecTimestamp4start}M-%{TX.ModSecTimestamp4end}M \
    TS-Phase5: %{TX.ModSecTimestamp5start}M-%{TX.ModSecTimestamp5end}M \
    Perf-Phase1: %{PERF_PHASE1}M \
    Perf-Phase2: %{PERF_PHASE2}M \
    Perf-Phase3: %{PERF_PHASE3}M \
    Perf-Phase4: %{PERF_PHASE4}M \
    Perf-Phase5: %{PERF_PHASE5}M \
    Perf-ReadingStorage: %{PERF_SREAD}M \
    Perf-WritingStorage: %{PERF_SWRITE}M \
    Perf-GarbageCollection: %{PERF_GC}M \
    Perf-ModSecLogging: %{PERF_LOGGING}M \
    Perf-ModSecCombined: %{PERF_COMBINED}M" perflog

    ErrorLogFormat "[%{cu}t] [%-m:%-l] %-a %-L %M"
    LogLevel debug

    ErrorLog logs/modsec-<MYVHOST>-error.log
    CustomLog  logs/modsec-<MYVHOST>-access.log extended
    CustomLog  logs/modsec-<MYVHOST>-perf.log perflog env=write_perflog


    # == ModSec Base Configuration

    SecRuleEngine                 On

    SecRequestBodyAccess          On
    SecRequestBodyLimit           10000000
    SecRequestBodyNoFilesLimit    64000

    SecResponseBodyAccess         On
    SecResponseBodyLimit          10000000

    SecTmpDir                     /tmp/
    SecUploadDir                  /tmp/

    SecDebugLog                   logs/modsec-<MYVHOST>-debug.log
    SecDebugLogLevel              0

    SecAuditEngine                RelevantOnly
    SecAuditLogRelevantStatus     "^(?:5|4(?!04))"
    SecAuditLogParts              ABEFHIJKZ

    SecAuditLogType               Concurrent
    SecAuditLog                   logs/modsec-<MYVHOST>-audit.log
    SecAuditLogStorageDir         logs/audit/

    SecDefaultAction              "phase:2,pass,log,tag:'Local Lab Service'"


    # == ModSec Rule ID Namespace Definition
    # Service-specific before Core Rule Set: 10000 -  49999
    # Service-specific after Core Rule Set:  50000 -  79999
    # Locally shared rules:                  80000 -  99999
    #  - Performance:                        90000 -  90199
    # Recommended ModSec Rules (few):       200000 - 200010
    # OWASP Core Rule Set:                  900000 - 999999


    # === ModSec timestamps at the start of each phase (ids: 90000 - 90009)

    SecAction "id:90000,phase:1,nolog,pass,setvar:TX.ModSecTimestamp1start=%{DURATION}"
    SecAction "id:90001,phase:2,nolog,pass,setvar:TX.ModSecTimestamp2start=%{DURATION}"
    SecAction "id:90002,phase:3,nolog,pass,setvar:TX.ModSecTimestamp3start=%{DURATION}"
    SecAction "id:90003,phase:4,nolog,pass,setvar:TX.ModSecTimestamp4start=%{DURATION}"
    SecAction "id:90004,phase:5,nolog,pass,setvar:TX.ModSecTimestamp5start=%{DURATION}"

    # SecRule REQUEST_FILENAME "@beginsWith /" \
    #    "id:90005,phase:5,t:none,nolog,noauditlog,pass,setenv:write_perflog"


    # === ModSec Recommended Rules (in modsec src package) (ids: 200000-200010)

    SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
      "id:200000,phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"

    SecRule REQUEST_HEADERS:Content-Type "application/json" \
      "id:200001,phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"

    SecRule REQBODY_ERROR "!@eq 0" \
      "id:200002,phase:2,t:none,deny,status:400,log,msg:'Failed to parse request body.',\
    logdata:'%{reqbody_error_msg}',severity:2"

    SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
    "id:200003,phase:2,t:none,log,deny,status:403, \
    msg:'Multipart request body failed strict validation: \
    PE %{REQBODY_PROCESSOR_ERROR}, \
    BQ %{MULTIPART_BOUNDARY_QUOTED}, \
    BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
    DB %{MULTIPART_DATA_BEFORE}, \
    DA %{MULTIPART_DATA_AFTER}, \
    HF %{MULTIPART_HEADER_FOLDING}, \
    LF %{MULTIPART_LF_LINE}, \
    SM %{MULTIPART_MISSING_SEMICOLON}, \
    IQ %{MULTIPART_INVALID_QUOTING}, \
    IP %{MULTIPART_INVALID_PART}, \
    IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
    FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"

    SecRule TX:/^MSC_/ "!@streq 0" \
      "id:200005,phase:2,t:none,deny,status:500,\
      msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"


    # === ModSec Core Rule Set Base Configuration (ids: 900000-900999)

    Include    modsecurity.d/crs/crs-setup.conf

    SecAction "id:900110,phase:1,pass,nolog,\
      setvar:tx.inbound_anomaly_score_threshold=5,\
      setvar:tx.outbound_anomaly_score_threshold=4"

    SecAction "id:900000,phase:1,pass,nolog,\
      setvar:tx.paranoia_level=1"


    # === ModSec Core Rule Set: Runtime Exclusion Rules (ids: 10000-49999)

    # ...


    # === ModSecurity Core Rule Set Inclusion

    Include    modsecurity.d/crs/rules/*.conf


    # === ModSec Core Rule Set: Startup Time Rules Exclusions

    # Disables 403 status code after login into the application
    SecRuleRemoveById 920420


    # === ModSec timestamps at the end of each phase (ids: 90010 - 90019)

    SecAction "id:90010,phase:1,pass,nolog,setvar:TX.ModSecTimestamp1end=%{DURATION}"
    SecAction "id:90011,phase:2,pass,nolog,setvar:TX.ModSecTimestamp2end=%{DURATION}"
    SecAction "id:90012,phase:3,pass,nolog,setvar:TX.ModSecTimestamp3end=%{DURATION}"
    SecAction "id:90013,phase:4,pass,nolog,setvar:TX.ModSecTimestamp4end=%{DURATION}"
    SecAction "id:90014,phase:5,pass,nolog,setvar:TX.ModSecTimestamp5end=%{DURATION}"


    # === ModSec performance calculations and variable export (ids: 90100 - 90199)

    SecAction "id:90100,phase:5,pass,nolog,\
      setvar:TX.perf_modsecinbound=%{PERF_PHASE1},\
      setvar:TX.perf_modsecinbound=+%{PERF_PHASE2},\
      setvar:TX.perf_application=%{TX.ModSecTimestamp3start},\
      setvar:TX.perf_application=-%{TX.ModSecTimestamp2end},\
      setvar:TX.perf_modsecoutbound=%{PERF_PHASE3},\
      setvar:TX.perf_modsecoutbound=+%{PERF_PHASE4},\
      setenv:ModSecTimeIn=%{TX.perf_modsecinbound},\
      setenv:ApplicationTime=%{TX.perf_application},\
      setenv:ModSecTimeOut=%{TX.perf_modsecoutbound},\
      setenv:ModSecAnomalyScoreInPLs=%{tx.anomaly_score_pl1}-%{tx.anomaly_score_pl2}-%{tx.anomaly_score_pl3}-%{tx.anomaly_score_pl4},\
      setenv:ModSecAnomalyScoreOutPLs=%{tx.outbound_anomaly_score_pl1}-%{tx.outbound_anomaly_score_pl2}-%{tx.outbound_anomaly_score_pl3}-%{tx.outbound_anomaly_score_pl4},\
      setenv:ModSecAnomalyScoreIn=%{TX.anomaly_score},\
      setenv:ModSecAnomalyScoreOut=%{TX.outbound_anomaly_score}"

</IfModule>

Troubleshooting:

Error parsing actions: Invalid quoted pair at position …

Wert nach ‚id:‘ in Single Quotes packen

‚Failed to resolve operator: detectxss‘ error while using Core Rule Set (CRS) v3.x

Es wurde mod_security < 2.8 installiert. Alle betreffenden Zeilen deaktivieren.

Sonstiges

mpm-Module in der Übersicht

Modul

Threads

Beschreibung

zu beachten

mpm_prefork_module

non-threaded

pre-forking

mod_php ok; funzt nicht mit dem http2_module

mpm_event_module

threaded

PHP-FPM ok, http2_module ok

mpm_worker_module

threaded

hybrid multi-process multi-threaded server

PHP-FPM ok, http2_module ok, mod_qos ok (nur eingeschränkt zusammen mit http2)

robots.txt

Beispiel für eine ausführliche robots.txt:

User-agent: AhrefsBot
Disallow: /

User-agent: AlphaBot
Disallow: /

User-agent: Baiduspider
Disallow: /

User-agent: Baiduspider-render
Disallow: /

User-agent: Buck
Disallow: /

User-agent: changedetection
Disallow: /

User-agent: Cliqzbot
Disallow: /

User-agent: Exabot
Disallow: /

User-agent: Flamingo_SearchEngine
Disallow: /

User-agent: Grobbot
Disallow: /

User-agent: JobboerseBot
Disallow: /

User-agent: jobs.de-Robot
Disallow: /

User-agent: linkdexbot
Disallow: /

User-agent: Mail.RU_Bot
Disallow: /

User-agent: Mediatoolkitbot
Disallow: /

User-agent: MegaIndex.ru/2.0
Disallow: /

User-agent: Mega-Index
Disallow: /

User-agent: MegaIndex.ru
Disallow: /

User-agent: MJ12bot
Disallow: /

User-agent: MojeekBot
Disallow: /

User-agent: Pinterestbot
Disallow: /

User-agent: rogerbot
Disallow: /

User-agent: SafeDNSBot
Disallow: /

User-agent: SemrushBot
Disallow: /

User-agent: SemrushBot/2~bl
Disallow: /

User-agent: SemrushBot-BA
Disallow: /

User-agent: SemrushBot-BM
Disallow: /

User-agent: SemrushBot-SA
Disallow: /

User-agent: SEOkicks-Robot
Disallow: /

User-agent: SeznamBot
Disallow: /

User-agent: SMTBot
Disallow: /

User-agent: spbot
Disallow: /

User-agent: trendictionbot
Disallow: /

User-agent: TweetmemeBot
Disallow: /

User-agent: vebidoobot
Disallow: /

User-agent: wonderbot
Disallow: /

User-agent: Wotbox
Disallow: /

User-agent: yacybot
Disallow: /

User-agent: YaK
Disallow: /

User-agent: YandexAntivirus
Disallow: /

User-agent: YandexBot/3.0
Disallow: /

User-agent: YandexImages
Disallow: /

User-agent: YandexMobileBot
Disallow: /

User-agent: Yeti
Disallow: /

Built on 2024-04-18