Seafile mit Fail2ban absichern
Seafile ist einer der zentralen Dienste eines jeden datamate Servers. Mit Seafile lassen sich Dateien – bei 100% Datensouveränität – bequem im Unternehmen verwalten und mit externen Geschäftspartnern teilen. Die Zugriffsmöglichkeit von Externen auf Seafile exponiert das System aber auch gegenüber Brute-Force-Angriffen. Bei solchen Angriffen werden automatisiert und orchestriert tausendfach Kombinationen aus Benutzername und Passwort ausprobiert. Ist das Passwort leicht zu erraten, erhält der Angreifer Zugriff auf das System und Daten können abgegriffen werden.
Seafile ist gegen Brute-Force-Angriffe nicht machtlos. Mit Captcha und anderen Schutzmechanismen bietet es einen Grundschutz. Das Schutzniveau von Seafile lässt sich mit ein wenig Aufwand aber noch deutlich verbessern. Darum geht es in diesem Artikel. Wir wollen zeigen, wie sich Seafile mit Hilfe des Logfile-Analysierers Fail2ban weiter absichern lässt. Das Prinzip des kleinen Programms ist denkbar einfach: Jeder Zugriffsversuch auf Seafile (egal ob ein Login-Versuch per Webbrowser bzw. per App, der Aufruf eines Up- oder Download-Links oder der Zugriff per WebDAV) wird in den Log-Dateien des Servers protokolliert. Wenn in einer gewissen Zeitspanne eine definierte Anzahl unauthentifizierte Zugriffe von einer IP-Adresse registriert werden, dann blockiert Fail2ban weitere Zugriffsversuche von dieser IP-Adresse für einen bestimmten Zeitraum. Bei geschickter Wahl dieser beiden Parameter sperrt man einen vergesslichen Mitarbeiter nicht aus, verhindert aber wirkungsvoll Brute-Force-Angriffe. Aus unserer Sicht ist diese Absicherung essentiell wichtig, sobald Seafile ins Internet freigegeben wird und sollte unter keinen Umständen ausgelassen werden.
Standard-Schutzmechanismen von Seafile
Standardmäßig verlangt Seafile nach mehreren fehlerhaften Login-Versuchen über das Webinterface Seahub die Eingabe eines Captchas. Eine solche Zusatzaufgabe ist für Menschen meist eine leicht zu lösende Aufgabe, für Computerprogramme aber – auch beim Einsatz von Mustererkennungsverfahren – weiterhin eine rechte harte Nuss. Captchas erschweren einen Einbruch mit der Brechstange ganz wesentlich und schützen daher recht zuverlässig gegen Brute-Force-Angriffe.
Nicht in den Schutzbereich der Captchas fallen die Benutzeranmeldungsversuche in den mobile Apps sowie der Aufruf von Up- und Download-Links. Bei letzteren verlässt man sich auf die Macht der langen, zufällig erzeugten Links. Deren Länge lässt sich in den Einstellung von Seafile festlegen. Standardmäßig haben die Links eine Länge von 10 Stellen und folgen dieser Struktur:
Downloadlink: seafile-url/d/XXXXXXXXXX Uploadlink: seafile-url/u/XXXXXXXXXX
Da jedes X eine Zahl zwischen 0-9 oder ein Buchstabe von a-f sein kann, gibt es insgesamt 16^10 mögliche Links – jeweils für Up- und Download-Links. Ausgeschrieben sind dies rund 1.000.000.000.000 mögliche Kombinationen. Klingt auf den ersten Blick gut. Da haben Haker einiges an Ausprobiererei vor sich, bis sie – auch bei strukturiertem Ausprobieren – auf einen Treffen stossen.
Vertrauen ist gut – Kontrolle ist besser
In Zeiten billiger Rechenleistung sollte man sich von großen Zahlen aber nicht täuschen lassen. Auch wenn 1 Billionen mögliche Kombinationen mächtig und nach einer solider Abwehrmaßnahme von strukturierten Angriffen klingt, so empfinden wir das als eine nicht vernachlässigbare Bedrohung. Warum zeigen wir mit folgendem Beispiel.
Das nachfolgende Skript probiert beispielsweise sämtliche dreistelligen Downloadlinks unter einer Domain aus, indem es die entsprechende URL per curl anfragt und auf den String “Sorry, but the requested page could not be found” prüft. Wenn dieser String gefunden wird, handelt es sich um eine Fehlerseite. D.h. unter dieser Adresse befindet sich kein aktiver Link. Andererseits bedeutet das Ausbleiben dieser Meldung, dass man auf eine gültige Download-Adresse gestossen ist.
#!/bin/bash ## Nur für lokale Demo-Zwecke. Dieses Skript auf einen fremden Server loszulassen, kann eine Straftat darstellen. start=`date +%s` log="/tmp/brute-force-seafile.log" echo "Brute-Force-Attack on Seafile Download-Links" > $log echo "---" >> $log for i in {a..f} {0..9}; do for j in {a..f} {0..9}; do for k in {a..f} {0..9}; do gotcha=`curl --insecure --location --silent --url "https://10.37.102.7/seafile/d/$i$j$k" | grep "Sorry, but the requested"` if [ -n "$gotcha" ]; then echo "/seafile/d/$i$j$k = -"; else echo "/seafile/d/$i$j$k = Treffer"; fi done; done; done end=`date +%s` runtime=$((end-start)) echo "Runtime was $runtime seconds." echo "--- finished ---"
Mit diesem Beispielskript konnten wir bei unseren Versuchen ungefähr 35 Kombinationen pro Sekunde abfragen. Dies mag im ersten Moment nicht viel erscheinen, da man bei dieser Geschwindigkeit ungefähr 1.000 Jahre benötigt, um die Billionen Kombinationen durchzuprobieren. Doch unsere bescheidenen Versuche sind genau das: Laienarbeit! Realistische Schlagzahlen bei orchestrierten Angriffen liegen um Größenordnungen darüber. Auch wenn unsere Stärke nicht im Hacking liegt, so fallen uns auf Anhieb mehrere Ansätze ein, mit denen sich ein Brute-Force-Angriff optimieren liesse:
- Jede Anfrage lädt den kompletten Quellcode der Webseite herunter, der dann nach dem String “Sorry, …” durchsucht wird. Mit Sicherheit lässt sich anhand von intelligenteren Rückgabewerten eine effizientere Suche realisieren.
- Jede Anfrage wird im Skript neu initialisiert. Curl bietet jedoch die Möglichkeit mit einer Sitzungsanfrage mehrere URLs anzufragen. So kann der Daten-Overhead reduziert werden.
- Wir haben nur ein Skript verwendet. Es können aber nahezu beliebig viele Skriptläufe parallelisiert werden. Das erste Skript prüft sämtliche Links mit “a” am Anfang, das zweite Skript alle Links mit “b”, etc pp.
- Bestimmt gibt es effizientere Wege als mit curl die Webseiteninhalte anzufragen.
Gleichzeitig sollte man nicht vergessen, dass man auch nicht bis zum Abschluß des Angriffs warten muss. Sobald die erste gültige URL gefunden wurde, lassen sich die dahinterliegenden Inhalte herunterladen. Das Angriffsszenario “Brute-Force” auf Seafile Download-Links ist somit aus unserer Sicht ein durchaus valides Szenario. Gerade wenn die in Aussicht stehenden Daten attraktiv sind, können große Energien freigesetzt werden.
Zum Glück lässt sich Seafile auf einfache Art und Weise gegen solche Angriffe abhärten. Das Programm Fail2ban steht dabei im Mittelpunkt. Davon handelt der Rest des Artikels. Wir fokussieren uns dabei auf die konkreten Maßnahmen zu Schutz von Seafile. Die Funktionsweise von Fail2ban haben wir bereits im Artikel Fail2ban: Automatisches System zur Erkennung und Verhinderung von Systemeinbrüchen ausführlich beschrieben.
Absicherung des Seafile Logins mit Fail2ban
Zunächst einmal schauen wir uns Angriffe auf den Web-Login an. Nach dem dritten fehlerhaften Login-Versuch findet man folgende Logeinträge in der seahub.log:
2016-10-06 07:27:46,461 [WARNING] seahub.auth.views:197 login Login attempt limit reached, show Captcha, email/username: mr_x, ip: 192.168.7.200, attemps: 3 2016-10-06 07:28:12,461 [WARNING] seahub.auth.views:197 login Login attempt limit reached, show Captcha, email/username: mr_x, ip: 192.168.7.200, attemps: 4
Diese lassen sich denkbar einfach mit Fail2ban abfangen. Zwei Schritte sind dazu notwendig: Die Anlage des Jails und die dazugehörige Definition des Filters.
Kümmern wir uns zunächst um den Jail. In dieser Konfigurationsdatei wird mit dem Parameter logpath die zu durchsuchende Log-Datei sowie die zu überwachende Zeit (findtime) und die dazugehörige Sperrzeit (bantime) in Sekunden festgelegt. Über den Parameter filter wird auf den anzuwendenden Filter verwiesen, den wir anschließend definieren. Die nachfolgende Beispielkonfiguration für den Jail seafile-login arbeitet für das HTTP und HTTPS Protokoll, überwacht die seahub.log unter /home/seafile/logs/ und sperrt eine IP-Adresse für 600 Sekunden aus, wenn für diese die Filterregel seafile-login innerhalb von 3.600 Sekunden fünfmal trifft. Kopiere diese Konfiguration einfach in die Datei jail.local unter /etc/fail2ban/ und passe die Werte nach belieben an.
# Seafile-Login Einstellungen in jail.local [seafile-login] enabled = true port = http,https filter = seafile-login logpath = /home/seafile/logs/seahub.log maxretry = 5 findtime = 3600 bantime = 600
Im nächsten Schritt muss nun der Fail2ban Filter definiert werden, auf den im Jail verwiesen wurde und nach der die angegebene Log-Datei durchsucht werden soll. Kopiere diesen Filter in die Datei seafile-login.conf im Verzeichnis /etc/fail2ban/filter.d/.
# filter.d/seafile-login.conf [Definition] failregex = .*Login attempt limit reached.*ip: <HOST>, att.* ignoreregex = # Author: Christoph Dyllick-Brenzinger (www.datamate.org)
Sobald man Fail2ban neu startet, sind sämtliche Logins per Webbrowser und per App geschützt. Teste die Einstellung nun. Tue dies aber zunächst mit einer geringen Bantime (z.B. bantime = 10), um Dich nicht für längere Zeit aus Deinem Server auszusperren.
Überwachung der Seafile Up- und Download-Links mit Fail2ban – Überwachung des Webservers nginx
Randomisiert erstellte Up- und Download-Links werden auch in anderen Software-Lösungen gerne genutzt, um Zugriffe von Unbefugten zu verhindern. Doch wie unser vorheriges Testskript gezeigt hat, können diese Links nicht als sicher angesehen werden. Ohne weitere Schutzmechanismen ist es nur eine Frage der Zeit, bis ein aktiver Link gefunden wird.
Das Vorgehen zur Absicherung des Link-Zugriffs mit Fail2ban erfolgt analog der Absicherung des Logins: In einem Jail wird das Verhalten von Fail2ban festgelegt, in einem Filter wird die Ergebnissuche definiert. Im Fall der Absicherung der Links in aktuellen Seafile Versionen muss man mit dem Filter nach den folgenden Einträgen in der seahub.access.log scannen:
192.168.5.45 - - [18/Oct/2016:16:51:59 +0200] "GET /d/1234567345/ HTTP/1.1" 404 1690 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/53.0.2785.143 Chrome/53.0.2785.143 Safari/537.36"
Der Eintrag in der jail.local von Fail2ban und der dazugehörige Filter lauten dann wie folgt:
# Seafile-Links Einstellungen in jail.local [seafile-url] enabled = true port = http,https filter = seafile-url logpath = /var/log/nginx/seahub.access.log maxretry = 10 findtime = 3600 bantime = 600
# filter.d/seafile-url.conf [Definition] failregex = <HOST>.*GET /(d|u|f)/.* 404 .* ignoreregex = # Author: Christoph Dyllick-Brenzinger (www.datamate.org)
Mit diesem Filter sind sowohl Folder-Download, File-Download und Uploads geschützt – vorausgesetzt, dass Seafile bei Dir nicht über einen Subfolder aufgerufen wird. Haben bei Dir die Seafile URLs eine andere Struktur, dann ist der Filter natürlich entsprechend anzupassen.
Überwachung der Seafile Up- und Download-Links – Seafile Logs durch eigene Middleware
Die Analyse der Log-Dateien des Webservers funktioniert zuverlässig. Gerade bei leistungsschwachen Geräten wie z.B. einem Raspberry Pi, empfehlen wir jedoch eine andere abgewandelte Art der Überwachung. Die Analyse der Log-Dateien des Webservers, die schnell ein paar Megabyte groß werden können, verlangen sonst einen ungebührlichen Anteil der Systemressourcen. Mit ein bisschen Arbeit kann man den Ressourcenaufwand deutlich reduzieren. Hierzu schreiben wir in Seafile eine eigene Django-Middleware, welche ganz gezielt die passenden Log-Einträge bei fehlerhaften Zugriffsversuchen schreibt.
Legen Sie die folgende Datei /seahub/seahub/base/ionas.py an:
import logging logger = logging.getLogger(__name__) class CustomLog(object): def process_response(self, request, response): if response.status_code == 404: ip_address = request.META.get('REMOTE_ADDR') url = request.META.get('PATH_INFO') logger.warn('|| Code: 404, IP: %s, URL: %s' % (ip_address, url )) return response
Wichtig: Achten Sie auf die richtige Einrückung der Zeilen, da diese nicht beliebig ist. Nun müssen wir noch diese Middleware in Seafile bekannt machen, damit die Log-Dateien richtig geschrieben werden.
Hierzu fügen wir in der /seahub/seahub/settings.py im Bereich MIDDLEWARE_CLASSES am Ende noch die folgende Zeile ein:
MIDDLEWARE_CLASSES = ( ... 'seahub.base.ionas.CustomLog', )
Zu guter Letzt wird Seafile noch neu gestartet und ab sofort wird jeder fehlerhafte Aufruf eines Up- oder Downloadslinks zu einer folgenden Fehlermeldung führen:
2016-10-06 07:23:16,281 [WARNING] seahub.base.ionas:10 process_response || Code: 404, IP: 192.168.7.200, URL: /u/d/114280491b
Diese Fehlermeldung kann man nun ganz einfach mit dem folgenden Filter abfangen und somit Brute-Force-Angriffe frühzeitig unterbinden.
# fail2ban filter configuration to protect the up-and downloadlinks of seafile against unlimited trial attempts [Definition] failregex = .*Code: 404, IP: <HOST>, URL:.* ignoreregex = # Author: Christoph Dyllick-Brenzinger (www.datamate.org)
Auch wenn dieser Ansatz etwas komplizierter erscheint, so bietet er zwei Vorteile:
1. Eigene Middleware ist ressourcenschonender
Da Fail2ban die Log-Dateien konstant auslesen muss, spielt die Dateigröße der Log-Dateien eine wichtige Rolle in Bezug auf die Ressourcenauslastung. Dieser Unterschied mag bei einem ausgewachsenen Server vernachlässigbar sein, ist jedoch bei einem Einplatingensystem wie dem Raspberry Pi nicht zu vernachlässigen.
2. Die Log-Datei ist auch für Menschen einfacher zu lesen
Der zweite Aspekt ist ein Komfortaspekt. Bei der unüberschaubaren Log-Datei von nginx kann es passieren, dass man den Wald vor lauter Bäumen nicht mehr sieht. Bei einer Log-Datei, die fast nur relevante Einträge hat, findet sich das menschliche Auge viel schneller und einfacher zurecht.
Einen Nachteil hat die eigene Middleware hingegen. Bei jedem Update von Seafile muss die Middleware neu integriert werden, da der Symlink seafile-server-latest auf ein neu hinzugekommenes Verzeichnis mit der neuesten Version zeigt.
Schützen Sie Ihr Seafile mit Fail2ban
Seafile bietet entgegen der kommerziellen Anbieter Dropbox und Google Drive die vollkommene Datenhoheit. Diese Hoheit verlangt jedoch, dass man sich mit der Sicherheit des Systems auseinandersetzt. Die Captchas von Seafile sind ein guter Grundschutz, sichern jedoch nicht alle Bereiche von Seafile zuverlässig.
Natürlich ist und bleibt das größte Sicherheitsrisiko der Mensch selbst, welcher aus Bequemlichkeit unsichere Passwörter verwendet und diese leichtfertig weitergibt. Doch mit Fail2ban lässt sich mit geringem Aufwand Seafile zuverlässig gegen Brute-Force-Angriffe absichern, weshalb dies ein Standardfeature eines jeden datamate Servers ist.