zurück zum Artikel

Die Apache-Firewall

Christiane Rütten

Die Application-Level-Firewall mod_security kann viel differenzierter auf den Inhalt von HTTP-Anfragen und -Antworten reagieren, als es mit herkömmlichen Paketfiltern möglich wäre.

Die wesentliche Einschränkung von Paket-filternden Firewalls wie IPTables und der Windows-Firewall besteht darin, dass sie im Grunde nichts von den Nutzdaten in den Paketen verstehen, die sie verarbeiten. Für sie ist nur wichtig, welche Pakete zu welcher Netzwerkverbindung gehören, woher sie kommen und wohin sie gehen. Application-Level-Firewalls hingegen verstehen die verarbeiteten Protokolle und können so viel differenzierter beispielsweise auf den Inhalt von HTTP-Verbindungen reagieren als dies auf Paketebene möglich wäre.

Die Probleme von Paketfiltern beginnen schon dabei, beispielsweise TCP-Pakete mit bekannten Exploits oder Webseiten mit schädlichen Links zu sperren. Zu suchende Muster befinden sich durch Fragmentierung nicht immer innerhalb eines einzelnen TCP-Paketes und die verwendeten Übertragungsprotokolle repräsentieren Daten häufig auch nicht in einem einheitlichen Format. Browser und Server würden den Deteipfad /docs/2.0/configuring.html zum Beispiel auch in der teilweise hexadezimal kodierten Form /%64o%63s/2%2E0/con%66igu%72ing%2Ehtml korrekt verarbeiten, was für die Erstellung von treffenden Suchmustern eine enorme Herausforderung darstellt. Entsprechend noch komplizierter wird die Angelegenheit bei der Erkennung von problematischen Inhalten in Variablenparametern in URLs oder gar POST-Anweisungen.

Darüber hinaus lässt sich von einem reinen Paketfilter auch nicht zuverlässig bestimmen, ob es sich bei den vorbeikommenden Paketen tatsächlich um Daten einer HTTP-Verbindung handelt. Der Ansatz, eine solche Zuordnung nach Ports vorzunehmen, scheitert in der Regel schon an den vielen Ausnahmen. So werden zur Umgehung restriktiver Firewalls viele Dienste, wie Internet-Telefonie, Filesharing oder Instant-Messenger ebenfalls über den HTTP-Port 80 abgewickelt. Die immer weitere Verbreitung SSL-verschlüsselter Verbindungen tut ihr Übriges, Paketfilter vom Protokollverständnis auszuschließen.

An diesem Punkt setzen Application-Level-Firewalls an. Wie der Name schon sagt, arbeiten sie nicht mehr wie Paketfilter auf der Netzwerk- und Transportschicht des OSI-Modells, sondern auf der Applikationsebene, über die die jeweiligen Anwendungen (in obigem Beispiel Browser und WWW-Server) miteinander kommunizieren. Hieraus leitet sich für diese Technik auch die alternative Bezeichnung Level-7-Filterung ab.

Im Falle von HTTP lässt sich eine Filterung auf Protokollebene noch recht bequem als Proxy realisieren. Doch es liegt nahe, die notwendige Funktionalität direkt in die Applikationen selbst zu integrieren, um eine engere Verzahnung und größere Flexibilität zu erreichen.

Die Application-Level-Firewall mod_security integriert sich als Apache-Modul direkt in den weit verbreiteten Webserver. Dadurch braucht sie sich nicht mehr mit den komplizierten Eigenheiten von TCP-Paketen zu beschäftigen, sondern hat ungestörten Zugriff auf alle Komponenten des HTTP-Protokolls. In den verarbeiteten Verbindungen lässt sich so nicht nur nach IP-Adressen filtern, sondern auf ebenso einfache Weise etwa in Variablen-Parametern von PHP-Skripten, Cookie-Namen und Informationen in HTTP-Headern suchen. Beispielsweise den Admin-Zugang des Forensystems phpBB auf eine bestimmte IP-Adresse einzuschränken, wird so zum Kinderspiel, wie die folgenden Beispiele zeigen.

Der Hersteller ThinkingStone hat den Quellcode unter GPL veröffentlicht, weshalb mod_security bereits Teil der meisten Linux-Distributionen ist, die den Apache-Webserver mitbringen. ThinkingStone selbst bietet den Quellcode als tar.gz-Archiv an. Er lässt sich entweder als Dynamic Shared Object (DSO), was einem selbständigen Apache-Modul entspricht, oder als so genannte Inline-Installation kompilieren, bei der die Quellen von mod_security direkt in die Apache-Quellen integriert werden. Details zu diesem Vorgehen, das Anwendern mit Erfahrung bei der Quellcode-Kompilierung vor keinerlei Überraschungen stellt, sind in der vorzüglichen englischen Dokumentation auf der Website von mod_security zu finden.

Der Einfachheit halber konzentriert sich dieser Artikel auf die Konfiguration von mod_security mit Apache2 unter Debian-Linux. Viele Webserver im Internet und auch der c't-Debian-Server[1 [1]] bauen auf dieser immer häufiger anzutreffenden Kombination auf. Wer bereits einen eigenen Apache-Webserver betreibt, wird die hier erläuterten Schritte leicht auch auf Apache 1.3 und andere Betriebsysteme übertragen können.

Mit Apache2 unter Debian genügt mit Root-Rechten ein einfaches

# apt-get install libapache2-mod-security
# a2enmod mod-security

um das Modul zu installieren und zu aktivieren. Eine simple Grundkonfiguration von mod_security mit einem Filterbeispiel sieht dann in der Datei /etc/apache2/conf.d/mod-security.conf wie folgt aus:

<IfModule mod_security.c>

SecFilterEngine On

# URL-Validierung aktivieren
SecFilterCheckURLEncoding On

# Unicode-Validierung aktivieren
SecFilterCheckUnicodeEncoding On

# HTTP-POST-Daten verarbeiten
SecFilterScanPOST On

# Standard-Aktion für zutreffende Filterregeln
SecFilterDefaultAction "deny,log,status:403"

# Filterregeln aus mod-security.d einbinden
Include /etc/mod-security.d/[^.#]*

</IfModule>

Das abschließende Include-Statement bindet sämtliche Dateien im Verszeichnis /etc/mod-security.d/ in alphabetischer Reihenfolge ein, die nicht mit einem Punkt oder dem Kommentarzeichen # beginnen. Dadurch ist es möglich, die diversen Regelsätze übersichtlich in einzelnen Dateien zu Gruppieren und zu verwalten. Eine einfache Filterregel in der Datei /etc/mod-security.d/beispiel.conf könnte dann so aussehen:

# Einfacher Demo-Filter
IncludeSecFilter /bin/sh
403-Fehlermeldung im Browser

Anfragen mit der Zeichenkette "/bin/sh" werden nur noch mit einer Fehlermeldung beantwortet.

Nach einem Neustart von Apache mit dem Befehl /etc/init.d/apache2 force-reload ist mod_security aktiv und der Webserver verarbeitet keine HTTP-Anfragen oder -Antworten mehr, die die Zeichenkette /bin/sh enthalten. Sobald das Suchmuster zutrifft, wird der Zugriff entsprechend der Anweisung SecFilterDefaultAction "deny,log,status:403" verweigert, der Vorfall im error.log von Apache protokolliert und dem vermeintlichen Einbrecher eine 403-Fehlermeldung präsentiert:

[Thu Jan 19 17:19:13 2006] [error] [client 127.0.0.1] mod_security: Access denied with code 403. Pattern match "/bin/sh" at THE_REQUEST [hostname "localhost"] [uri "/index.php?exec=/bin/sh%20/var/www/upload/x.sh"]

Die einfachen Filterregeln von mod_security haben das Format SecFilter AUSDRUCK [AKTION] und werden folgendermaßen interpretiert: Wenn der angegebene Suchausdruck (genau genommen ein regulärer Ausdruck) auf eine ein- oder ausgehende HTTP-Anfrage zutrifft, wird die angegebene Aktion ausgeführt. Ist keine Aktion explizit angegeben, wird die durch die Konfigurationsoption SecFilterDefaultAction spezifizierte Aktion durchgeführt.

Die möglichen Aktionen, von denen sich für eine Filterregel auch mehrere durch Komma getrennt angeben lassen, sind in vier Klassen eingeteilt:

Eine vollständige Liste aller Aktionen und Parameter befindet sich in der Dokumentation auf der mod_security-Homepage [1 [2]].

Bei genauerer Betrachtung erweist sich die Arbeit mit SecFilter schnell als zu ungenau. Es werden stets die vollständige Anfrage sowie die gesamten bei POST-Zugriffen übertragenen Daten durchsucht. Dies führt in der Regel zu schwer vorhersehbaren False-Positives und sollte nur sehr bedacht eingesetzt werden. Wesentlich feinere Abfragen lassen sich mit SecFilterSelective erzielen, welches vor dem eigentlichen Suchmuster noch eine oder mehrere durch das Pipe-Symbol | getrennte Ortsangaben benötigt, auf die die Suche eingeschränkt werden soll. Ersetzt man in obiger Minimalkonfiguration die Filterregel durch folgenden Block aus Beispiel-Regeln, rückt mod_security nach einem Apache-Reload ab von dem ungenauen Schrotschussverfahren:

SecFilterSelective ARGS "wget\x20"
SecFilterSelective ARGS "<[[:space:]]*script"
SecFilterSelective ARG_highlight "%27"
SecFilterSelective ARG_username "^admin$" chain
SecFilterSelective REMOTE_ADDR "!^192.168.0.2$"

In der ersten Filterregel ist zusätzlich zum einfachen Suchmuster als Ort ARGS angegeben. Das Suchmuster wird dadurch lediglich auf die Variablen-Argumente der Anfrage losgelassen, und zwar sowohl auf die Argumente hinter der URL als auch auf Argumente, die in einem eventuellen POST-Request übermittelt werden.

Der in der zweiten Filterregel angegebene reguläre Ausdruck schlägt bei vielen gängigen Cross-Site-Skripting-Angriffen an, die in der Regel darauf angewiesen sind, Script-Tags in HTTP-Anfragen einzubetten.

Die dritte Filterregel ist speziell auf HTTP-Requests des phpBB-Wurms Santy.A ausgelegt. Dieser versuchte durch geschickt platzierte Hochkommata (%27 entspricht dem Zeichen ') in der Variablen highlight, eine kritische Lücke in dem Forensystem zur Ausführung von beliebigem Schad-Code auszunutzen.

Die vierte Filterregel liefert ein Beispiel für eine Verkettung mit der folgenden Regel durch chain: Das Forensystem phpBB übergibt den Benutzernamen in der POST-Variablen username. Somit trifft der angegebene reguläre Ausdruck auf Login-Versuche eines Administrators namens "admin" zu. In diesem Fall kommt die folgende Filterregel zur Ausführung, die den Zugriff verweigert, wenn der anfragende Rechner nicht die IP-Adresse 192.168.0.2 besitzt. Kurz gefasst, beschränken die beiden letzten Regeln einen Admin-Login für phpBB auf besagte IP-Adresse.

mod_security kennt viele weitere Suchorte. Beispielsweise ist es möglich, den Namen einer der bekannten CGI-Variablen wie REMOTE_ADDR anzugeben, um deren Wert zu überprüfen. Spezielle Orte wie COOKIE_NAMES oder HEADERS schränken die Suche auf Namen von Cookies beziehungsweise auf den Header der HTTP-Anfrage ein. Die vollständige Liste der unterstützend Suchorte ist auf der mod_security-Homepage [1 [3]] dokumentiert.

Besonderes Augenmerk fällt auf die Aktion exec, mit der es möglich ist, aus mod_security heraus externe Programme oder Skripte in zu starten. Dadurch lässt sich das Apache-Modul auf einfache Weise einsetzen, um beispielsweise den Server-Zugriff für kompromittierte Rechner schon auf Paketfilter-Ebene vollständig zu blockieren, wie das folgende Beispiel zeigt.

Es ist nicht möglich, den so aufgerufenen Programmen und Skripten Kommandozeilenoptionen zu übergeben. Dies muss über geeignete Umgebungsvariablen erfolgen. Sämtliche CGI-Variablen, wie beispielsweise THE_REQUEST, TIME, REMOTE_USER und DOCUMENT_ROOT stehen den aufgerufenen Programmen als Umgebungsvariablen zur Verfügung. Ausserdem lassen sich durch die Aktion setenv:VARIABLE=WERT eigene Umgebungsvariablen setzen, um mit Skripten und Programmen zu kommunizieren.

Das folgende Beispiel implementiert ein einfache Blacklisting. Zunächst ist dazu in obigem Beispiel die Zeile zur Erkennung von Santy.A-Zugriffen

SecFilterSelective ARG_highlight "%27"

mit dem entsprechenden Skriptaufruf zu versehen:

SecFilterSelective ARG_highlight "%27" \
"deny,log,exec:/etc/mod-security/ip-blacklist.sh"

Das Skript /etc/mod-security/ip-blacklist.sh hängt lediglich die in der CGI-Variable REMOTE_ADDR gespeicherte IP-Adresse, von der aus der Zugriff getätigt wurde, an eine Blacklist-Datei im Logverzeichnis von Apache an:

#!/bin/sh
echo ${REMOTE_ADDR} >>/var/tmp/blacklist

Um die IP-Adressen in der Blacklist tatsächlich zu blocken, ist nun beispielsweise noch ein mit Root-Rechten laufender Hintergrund-Job notwendig, der die Blacklist auf Änderungen überprüft und in der Firewall durch entsprechende iptables-Aufrufe die Sperrung der IPs veranlasst. Das folgende sehr einfach gehaltene Skript erfüllt diese Aufgabe für den lokalen Paketfilter des Servers:

#!/bin/sh

BLACKLIST=/var/tmp/blacklist

touch ${BLACKLIST} ; chown www-data:www-data ${BLACKLIST}
tail -f ${BLACKLIST} | while read ip
do
iptables -A INPUT -s ${ip} -j DROP
done

Ein Skript für den realen Einsatz sollte auch auf doppelte Einträge prüfen und aus Sicherheitsgründen den Inhalt der Datei unbedingt rigiden Tests unterziehen, bevor es ihn in irgendwelche Befehle einbettet. Außerdem ist ein automatisierter Mechanismus zur Sperrung verdächtiger IPs immer mit großer Vorsicht zu genießen. Einerseits finden die Zugriffe möglicherweise nicht direkt von den IPs böswilliger Rechner aus statt, sondern über einen Proxy-Server. Dessen Nutzerschaft würde so unberechtigter Weise vollständig vom Serverzugriff ausgeschlossen. Andererseits ließe sich ein automatisierter Mechanismus zur Firewall-Administration unter Umständen auch von einem Angreifer missbrauchen, um Zugriff auf privilegierte Bereiche zu erlangen oder unbeteiligte Nutzer auszusperren. Im Falle eines Distributed-Denial-Of-Service-Angriffs wäre allerdings auch dieses Mittel recht, um die ressourcenfressenden Anfragen gänzlich vom Server-Prozess fern zu halten.

Die oben angebebene Basiskonfiguration ohne die Beispielregeln lässt sich leicht für vorgefertigte Filterregelsätze nutzen, wie sie vielerorts im Internet angeboten werden. Ein besonders umfangreiches Angebot an aktuellen Filterregeln findet sich beispielweise bei Got Root[3 [4]]. Es deckt ein breites Spektrum bekannter Schadsoftware und manipulativer Serverzugriffe ab. Folgende Befehle laden einen aktuellen Filterregelsatz und integrieren ihn in die bereits erstellte Apache-Konfiguration:

# cd /tmp
# wget http://www.gotroot.com/\
downloads/ftp/mod_security/apache2/\
apache2-gotrootrules-latest.tar.bz2
# tar jxf apache2-gotrootrules-latest.tar.bz2
# cd apache2
# mv exclude.conf 0-exclude.conf
# mv rules.conf \#rules.conf
# mv recons.conf \#recons.conf
# mv * /etc/mod-security.d/

Die Datei exclude.conf stellt gewissermaßen eine Whitelist für bekannte Ausnahmen dar. Sie muss daher umbenannt werden, um sie vor den anderen Regeldateien einbinden zu lassen. Die beiden Regelsätze rules.conf und recons.conf enthalten Regeln, die mod_security erst seit version 1.9.0 unterstützt und müssen daher deaktiviert werden. Der letzte Schritt kann beim Einsatz einer 1.9er Version entfallen, doch Debian liefert derzeit Binärpakete nur für Version 1.8.7.

Bei Web-Servern mit mehreren Blogs, Foren und anderen PHP-Programmen kommt es bei umfangreichen Filterregelsätzen schnell auch zu falschen Treffern, so genannten false positives. Daher ist es grundsätzlich ratsam, das Verhalten neuer Filterregeln über einen längeren Zeitraum im Produktivbetrieb zu beobachten, bevor Zugriffe auf deren Grundlage tatsächlich blockiert werden. Dazu genügt es, SecFilterDefaultAction in /etc/apache2/conf.d/mod-security.conf auf "pass,log" statt des bisher verwendeten "deny,log,status:403" zu setzen.

Standardmäßig meldet mod_security zutreffende Filterregeln im Fehler-Log von Apache. Ein

# tail -f /var/log/apache2/error.log | grep mod_security

in der Kommandozeile genügt, um dem Modul bei der Arbeit zuzusehen. Wer umfangreichere Informationen über die Vorgänge benötigt, kann folgende Zeilen in /etc/apache2/conf.d/mod-security.conf einfügen:

SecAuditEngine RelevantOnly
SecAuditLog /var/log/apache2/mod-security.log

Durch die in der angegebenen Logdatei protokollierten Informationen lassen sich leicht störende Filterregeln und die dahinter stehenden Ursachen ausfindig machen.

Der Performanceverlust durch das Filtern mit mod_security hängt natürlich sehr stark vom Regelwerk ab, konkrete Zahlen können nur eigene Tests liefern. Erfahrungsberichte im Web sprechen typischerweise von einer um rund 10 Prozent erhöhten Systemlast. In der Praxis lässt sich die Performance-Einbuße von mod_security noch weiter verringern, indem statische Anfragen, beispielsweise nach reinen HTML-Dateien, Stylesheets und Bildern mit

SecFilterEngine DynamicOnly

grundsätzlich von der Filterung ausgeschlossen werden.

Erst wer sich die umfangreiche Dokumentation auf der Website von mod_security zu Gemüte führt, kann einen guten Überblick über dessen Funktionsvielfalt erlangen. Insbesondere sei noch auf die Möglichkeiten zur Filterung ausgehender Server-Antworten, den weitgehend konfigurierbaren Logging-Machanismus und die diversen Aktionen und Suchorte für erweiterte Filterregeln hingewiesen.

mod_security ist ein mächtiges Werkzeug, das Gelegenheitsadministratoren schnell durch den Wartungsaufwand überfordern kann. Einerseits ist es sehr einfach, eine Basiskonfiguration aufzusetzen und Zugriffe mit gewissen Schlüsselbegriffen zu sperren oder auf gewisse IPs zu beschränken. Doch andererseits kommt es leicht zu Konflikten mit bereits installierten PHP-Programmen, die es durch geeignete, umfangreiche Tests im Voraus auszuschließen gilt. Auch die Möglichkeit, aktuelle Filterregelsätze aus dem Internet zu beziehen, befreit nicht von dieser Aufgabe, möchte man keine unerwarteten Probleme beim Zugriff auf seine Server erleben.

Für hochsichere und gut getestete Server hingegen ist mod_security ein mächtiges Werkzeug, das sich ohne große Probleme auch zu einem umfangreichen Intrusion-Prevention-System ausbauen lässt. Auch hat sich das Apache-Modul bereits im Kampf gegen andauernde Angriffe bewährt, wie beispielsweise beim DDoS-Angriff Ende 2005 gegen das Portal gulli.com. Admins sollten aber nicht vergessen, dass ein eng geschnürtes Intrusion-Prevention-Korsett ebenso pflegebedürftig ist, wie die Server-Applikationen, die es schützen soll.

[1] http://www.modsecurity.org/ [5], Homepage von mod_security

[2] Homepage des c't-Debian-Server [6]

[3] http://www.gotroot.com/mod_security+rules [7], aktuelle Filterregelsätze für mod_security (cr [8])


URL dieses Artikels:
https://www.heise.de/-270782

Links in diesem Artikel:
[1] #uelit-u4
[2] #uelit-u4
[3] #uelit-u4
[4] #uelit-u4
[5] http://www.modsecurity.org/
[6] http://www.heise.de/ct/ftp/projekte/srv/
[7] http://www.gotroot.com/mod_security+rules
[8] mailto:cr@ct.de