Apache gegen Denial-of-Service-Attacken wappnen

Die Entdeckung der Langsamkeit

Besonders perfide Angriffe gegen Apache simulieren langsame Clients und hungern damit den Webserver aus. Ein paar administrative Maßnahmen minimieren die Auswirkungen und steigern nebenbei noch die Leistungsfähigkeit des Servers.

Ein kleines Gedankenexperiment: Sie wollen einen Webserver schreiben, also programmieren Sie einen Socket-basierten Server. Wenn sich ein Browser mit ihm verbindet und eine Datei anfordert, liefert er sie aus, der Client beendet die Verbindung und jeder ist zufrieden. Aber dann gibt es auf einmal einen Bug-Report von jemand, dessen Webserver immer langsamer und langsamer wird, bis er irgendwann gar nicht mehr reagiert. Was nun?

Als Sie sich Problem näher ansehen, stellen Sie fest, dass einige Clients sich nicht verhalte wie vorgesehen: Sie bauen eine Verbindung auf, machen dann aber nichts und schließen sie auch nicht mehr. Das Ergebnis davon ist, dass der Server irgendwann keine neuen Verbindungen mehr aufbauen und somit keine neuen Clients mehr bedienen kann. Der Fix dafür ist einfach: Sie bauen in den Server einen Timeout ein, sodass er Verbindungen nach einer bestimmten Zeit abbricht, wenn nichts passiert. In der Konfigurationsdatei ist der Zeitraum über die Direktive »TimeOut« einstellbar.

Das funktioniert eine Weile lang gut, aber die Welt dreht sich weiter und irgendwann sind Webseiten nicht länger nur einzelne HTML-Dateien, sondern eine Sammlung von HTML, Bildern, CSS-Stylesheets und Javascript-Dateien. Für jede eine einzelne Verbindung aufzubauen, dauert relativ lange, zum Beispiel schon weil Client und Server jedes Mal aufs Neue den TCP-Threeway-Handshake absolvieren müssen [1]. Also denken Sie sich etwas schlaues aus: Der Client kann die erste Verbindung offen halten und darüber alle weiteren Dateien anfordern, die er braucht. Jetzt sind die zweite, die dritte und alle weiteren Anfragen viel schneller beantwortet und wieder sind alle zufrieden. Weil Sie aus dem obigen Problem etwas gelernt haben, sehen Sie eine weitere Konfigurationsoption namens »KeepAliveTimeout« vor, die verhindert, dass Clients Verbindungen unendlich lang belegen. Bald laden sich alle Webadministratoren Ihren tollen neuen Webserver herunter und unter dem Namen Apache hat er schon bald einen Marktanteil von 60 Prozent.

Gesunde Einstellung

Das Problem mit solchen Einstellungen wie Timeouts ist, dass die meisten Default-Werte nicht für jede Anwendung funktionieren. Site A liefert vielleciht Millionen kleiner statischer Bilder aus, während Site B ein umfangreiches dynamisches Framework für alle Inhalte verwenden, und die Sites C bis Z wissen eigentlich gar nicht so genau, was sie machen. Aber was soll's, der Webserver funktioniert ja einigermaßen, also weshalb sich groß um die Default-Werte scheren? Auch die Linux-Distributoren ändern kaum einmal die Default-Einstellungen an ausgelieferten Paketen, denn das wäre wahnsinnig viel Arbeit. Also muss der Endanwender meistens dem Software-Projekt bei der Wahl der Voreinstllungen vertrauen – schließlich verstehen die Programmierer doch ihre Software am besten. Das ist dann der Grund dafür, warum man einen Webserver betreibt, der recht gut funktioniert, solange nichts Ungewöhnliches passiert, wie zum Beispiel, dass sich 1000 Clients über sehr langsame Leitungen mit dem Server verbinden – oder ein Client, mit 1000 Verbindungen, die so tun, als ob sie über eine langsame Leitung liefen.

In diesem Fall stellt der Webserver sehr schnell die Arbeit ein. Das heißt, er funktioniert eigentlich noch, aber er ist in seiner Handlungsfähigkeit stark eingeschränkt. Wenn also die Abfertigung von 1000 Requests keinen großen Aufwand bedeutet, hat der Server unter Umständen doch keine Ressource mehr um legitime Anfragen zu beantworten. Böswillige Menschen können diese Situation für einen Angriff von einem einzigen Computer aus nutzen, der nicht einmal über eine besonders schnelle Netzwerkanbindung verfügen muss. Cracker-Tools wie Slowloris helfen ihm noch dabei [2] (Abbildung 1).

Abbildung 1: Der Entwickler mit dem Pseudonym RSnake präsentiert die Slowloris-Attacke auf der Defcon 17.

Man könnte einfach die Anzahl von Verbindungen für eine IP-Adresse oder einen gewissen Bereich begrenzen. Das ist allerdings schlecht, wenn Clients sich hinter einem Proxy befinden, denn dann tauchen alle beim Server mit der gleiche Adresse auf. Die Schwierigkeit für den Admin liegt darin, eine Zahl zu finden, die Schaden vom Server abwendet, aber legitime Anwender nicht behindert.

Ein generischer Ansatz für eine solche Begrenzung führt über das Rate-Limit von IPTables, das auch auf einzelne Ports anwendbar ist. Damit ist es ist möglich, die maximale Anzahl Verbindungen in eine bestimmten Zeitraum festzulegen. Die folgenden Anweisungen erlauben in 60 Sekunden maximal fünf Verbindungen. Bei der sechsten und den folgenden verwirft (drop) IPTables die Datenpakete, was dazu führt, dass der Client es weiter versucht. Wenn eine frühere Verbindung geschlossen wird, erlaubt die Regel eine neue.

iptables -I INPUT -p tcp --dport 80 -m state↩
 --state NEW -m recent --set
iptables -I INPUT -p tcp --dport 80 -m state↩
 --state NEW -m recent --update --seconds 60↩
 --hitcount 6 -j DROP

Ein Angreifer, der es wirklich darauf anlegt, wird vermutlich mehrere Rechner eines Botnets verwenden, aber immerhin kann man ihm das Leben etwas schwerer machen.

Die einfachste Methode gegen die Slowloris-Attack besteht darin, das »TimeOut« von seinem Default-Wert 300 auf fünf Sekunden zu setzen. Um den Missbrauch von HTTP-Keepalive zu verhindern, können Sie es ausschalten, indem Sie »KeepAlive« auf »off« setzen. Keine dieser Maßnahmen verschafft völlige Immunität, vor allem nicht gegen Angreifer mit viel Ressource, aber meistens helfen sie [3]. Übrigens ist nicht nur Apache von der Slowloris-Attacke betroffen, sondern auch der Squid-Proxy und einige andere Webserver.

Langzeitschutz

Auch wenn völlige Sicherheit gegen Denial-of-Service-Attacken nicht möglich ist. kann man Systeme aufsetzen, die kleinere Angriffe überstehen und zumindest den Aufwand für Angreifer nach oben treiben. Langfristig scheint die beste Lösung zu sein, intelligente Schutzmechanismen direkt in die Anwendungen einzubauen und vorallem ihnen zu erlauben, dynamisch ihre Einstellungen selbst anzupassen. So könnten sie das Connection-Timeout reduzieren, wenn sie mehr Anfragen erhalten, oder dann Verbindungen zu langsamen Clients einfach kappen. Auf diese Weise würden Anwendungen nicht nur Denial-of-Service-Attacken überstehen, sondern generell auch für hohe Last besser gewappnet sein.

Ein Beispiel dafür ist der Apache-Patch von Andreas Krennmair [4], der den Webserver gegen Slowlaris-Angriffe wappnet. Er überwacht die Webserver-Last mit Hilfe des Apache-Scoreboards. Wenn die Load steigt, passt er den Timeout-Wert an: Bei 60 Prozent halbiert er den Timeout, bei 70 Prozent reduziert er ihn auf ein Viertel und so weiter. Obwohl recht einfach gestrickt, ist dieser Patch ein gutes Beispiel dafür, wie man etwas Intelligenz und "Überlebensinstinkt" in eine Software integriert. Leider kann der Patch keine bestehenden Verbindungen beenden, ein Angreifer mit genügend Ressourcen kann den Server also immer noch lahm legen.

comments powered by Disqus