Ich schreibe einen HTTP-Server-Daemon in C (es gibt Gründe dafür) und verwalte ihn mit systemd unit file.
Ich schreibe eine Anwendung um, die vor 20 Jahren, um 1995, entworfen wurde. Und das System, das sie verwenden, ist, dass sie chroot und dann setuid und das Standardverfahren.
In meiner vorherigen Arbeit war die übliche Richtlinie, dass Sie niemals einen Prozess als root ausführen. Sie erstellen dafür einen Benutzer / eine Gruppe und führen sie von dort aus. Natürlich hat das System einige Dinge als root ausgeführt, aber wir konnten die gesamte Geschäftslogikverarbeitung erreichen, ohne root zu sein.
Jetzt kann ich den HTTP-Daemon ohne root ausführen, wenn ich nicht in der Anwendung chroot bin. Ist es nicht sicherer, dass die Anwendung niemals als Root ausgeführt wird?
Ist es nicht sicherer, es von Anfang an als mydaemon-Benutzer auszuführen? Anstatt es mit root, chrooting und setuid zu mydaemon-user zu starten?
capabilities(7)
.Antworten:
Es sieht so aus, als hätten andere Ihren Standpunkt verfehlt, was nicht der Grund dafür war, geänderte Wurzeln zu verwenden, die Sie natürlich bereits genau kennen, oder was Sie sonst noch tun können, um den Dæmons Grenzen zu setzen, wenn Sie auch genau wissen, wie man unter den Ägide von läuft nicht privilegierte Benutzerkonten; aber warum diese Dinge zu tun in der Anwendung . Es gibt tatsächlich ein gutes Beispiel dafür, warum.
Betrachten Sie das Design des
httpd
dæmon-Programms in Daniel J. Bernsteins Publicfile-Paket. Als Erstes wird root in das Stammverzeichnis geändert, das mit einem Befehlsargument verwendet werden soll, und anschließend werden Berechtigungen für die nicht privilegierte Benutzer-ID und Gruppen-ID gelöscht, die in zwei Umgebungsvariablen übergeben werden.Die Management-Toolsets von Dæmon verfügen über spezielle Tools zum Ändern des Stammverzeichnisses und zum Löschen von nicht privilegierten Benutzer- und Gruppen-IDs. Gerrit Papes Runit hat
chpst
. Mein nosh Toolset hatchroot
undsetuidgid-fromenv
. Laurent Bercots s6 hats6-chroot
unds6-setuidgid
. Wayne Marshalls Täter hatruntool
undrunuid
. Und so weiter. Tatsächlich haben sie alle M. Bernsteins eigenes daemontools-Toolsetsetuidgid
als Vorläufer.Man könnte denken, dass man die Funktionalität aus
httpd
solchen dedizierten Werkzeugen extrahieren und verwenden könnte. Dann wird, wie Sie sich vorstellen, kein Teil des Serverprogramms jemals mit Superuser-Rechten ausgeführt.Das Problem ist, dass man als direkte Folge erheblich mehr Arbeit aufwenden muss, um die geänderte Wurzel aufzubauen, was neue Probleme aufwirft.
Bei Bernstein
httpd
sind die einzigen Dateien und Verzeichnisse im Stammverzeichnisbaum diejenigen, die für die Welt veröffentlicht werden sollen. Es gibt überhaupt nichts anderes im Baum. Darüber hinaus gibt es keinen Grund dafür, dass in diesem Baum eine ausführbare Programm-Image-Datei vorhanden ist.Aber bewegen ändert die Root - Verzeichnis in ein Kette-Ladeprogramm (oder systemd), und plötzlich die Programm Bilddatei für
httpd
beliebigen Shared Libraries , dass es geladen wird , und spezielle Dateien in/etc
,/run
und/dev
dass der Programmlader oder C - Laufzeitbibliothek Zugangs während Programminitialisierung (die Sie finden können ziemlich überraschend , wenn Sietruss
/strace
ein C oder C ++ Programm), auch in der veränderten Wurzel sein. Andernfallshttpd
kann nicht angekettet werden und wird nicht geladen / ausgeführt.Denken Sie daran, dass dies ein HTTP (S) -Inhaltsserver ist. Es kann möglicherweise jede (weltweit lesbare) Datei im geänderten Stammverzeichnis bereitstellen. Dies umfasst jetzt Dinge wie Ihre gemeinsam genutzten Bibliotheken, Ihren Programmlader und Kopien verschiedener Loader- / CRTL-Konfigurationsdateien für Ihr Betriebssystem. Und wenn durch eine (zufällige) bedeutet , dass die Content - Server - Zugriff hat Schreib Zeug, ein kompromittierte Server möglicherweise Schreibzugriff auf das Programmbild für gewinnen kann
httpd
selbst oder sogar Programmlader Ihres Systems. (Denken Sie daran , dass Sie haben jetzt zwei parallele Sätze von/usr
,/lib
,/etc
,/run
, und/dev
Verzeichnisse sicher zu halten.)Dies ist jedoch nicht der Fall, wenn
httpd
Root-Rechte geändert und Berechtigungen selbst gelöscht werden.Sie haben also mit einer kleinen Menge privilegierten Codes gehandelt, der ziemlich einfach zu überwachen ist und der direkt zu Beginn des
httpd
Programms mit Superuser-Rechten ausgeführt wird. für eine stark erweiterte Angriffsfläche von Dateien und Verzeichnissen innerhalb des geänderten Stamms.Deshalb ist es nicht so einfach, alles außerhalb des Serviceprogramms zu erledigen.
Beachten Sie, dass dies dennoch ein Minimum an Funktionalität in
httpd
sich ist. Der gesamte Code, mit dem beispielsweise in der Kontodatenbank des Betriebssystems nach der Benutzer-ID und der Gruppen-ID gesucht wird, um diese Umgebungsvariablen überhaupt erst zu erstellen, befindet sich außerhalb deshttpd
Programms und wird in einfachen, eigenständigen, überprüfbaren Befehlen wie zenvuidgid
. (Und natürlich ist es ein ucspi Werkzeug, so dass es enthält keine der Code auf der entsprechenden TCP - Port zu hören (n) oder Verbindungen zu akzeptieren, diejenigen sind die Domäne der Befehle wietcpserver
,tcp-socket-listen
,tcp-socket-accept
,s6-tcpserver4-socketbinder
,s6-tcpserver4d
, und so weiter.)Weitere Lektüre
httpd
. publicfile . cr.yp.to.httpd
. Daniel J. Bernsteins Software in einem . Software. Jonathan de Boyne Pollard. 2016.gopherd
. Daniel J. Bernsteins Software in einem . Software. Jonathan de Boyne Pollard. 2017.quelle
Ich denke, dass viele Details Ihrer Frage gleichermaßen zutreffen könnten
avahi-daemon
, die ich kürzlich angeschaut habe. (Ich könnte ein anderes Detail übersehen haben, das sich jedoch unterscheidet). Das Ausführen von avahi-daemon in einer Chroot hat viele Vorteile, falls avahi-daemon gefährdet ist. Diese beinhalten:Punkt 3 könnte besonders nützlich sein, wenn Sie keinen Dbus oder ähnliches verwenden ... Ich denke, Avahi-Daemon verwendet Dbus, sodass sichergestellt ist, dass der Zugriff auf den System-Dbus auch von innerhalb der Chroot aus möglich ist. Wenn Sie nicht in der Lage sein müssen, Nachrichten auf dem System-D-Bus zu senden, ist es möglicherweise eine nette Sicherheitsfunktion, diese Fähigkeit zu verweigern.
Beachten Sie, dass avahi-daemon, wenn es neu geschrieben wurde, sich möglicherweise aus Sicherheitsgründen auf systemd verlassen und z
ProtectHome
. Ich habe eine Änderung an Avahi-Daemon vorgeschlagen, um diese Schutzfunktionen als zusätzliche Ebene hinzuzufügen, zusammen mit einigen zusätzlichen Schutzfunktionen, die von Chroot nicht garantiert werden. Die vollständige Liste der von mir vorgeschlagenen Optionen finden Sie hier:https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a
Es sieht so aus, als gäbe es weitere Einschränkungen, die ich hätte anwenden können, wenn avahi-daemon nicht chroot selbst verwendet hätte, von denen einige in der Festschreibungsnachricht erwähnt sind. Ich bin mir nicht sicher, wie viel dies gilt.
Beachten Sie, dass die von mir verwendeten Schutzfunktionen den Daemon nicht daran gehindert hätten, Unix-Socket-Dateien zu öffnen (siehe Punkt 3 oben).
Ein anderer Ansatz wäre die Verwendung von SELinux. Allerdings würden Sie Ihre Anwendung an diese Untergruppe von Linux-Distributionen binden. Der Grund, warum ich SELinux hier positiv fand, ist, dass SELinux den Zugriff, den Prozesse auf dbus haben, auf feinkörnige Weise einschränkt. Ich denke zum Beispiel, dass Sie oft erwarten können, dass
systemd
dies nicht in der Liste der Busnamen enthalten ist, an die Sie Nachrichten senden müssen :-)."Ich habe mich gefragt, ob die Verwendung von systemd-Sandboxen sicherer ist als chroot / setuid / umask / ..."
Zusammenfassung: Warum nicht beides? Lass uns das obenstehende ein wenig dekodieren :-).
Wenn Sie an Punkt 3 denken, bietet die Verwendung von Chroot mehr Einschränkungen. ProtectHome = und seine Freunde versuchen nicht einmal, so restriktiv wie chroot zu sein. (Zum Beispiel keine der genannten Systemd-Options-Blacklists
/run
, in denen wir Unix-Socket-Dateien ablegen).chroot zeigt, dass das Einschränken des Dateisystemzugriffs sehr mächtig sein kann, aber nicht alles unter Linux ist eine Datei :-). Es gibt systemd-Optionen, die andere Dinge einschränken können, die keine Dateien sind. Dies ist nützlich, wenn das Programm kompromittiert ist. Sie können die verfügbaren Kernelfunktionen reduzieren, um eine Sicherheitsanfälligkeit auszunutzen. Zum Beispiel benötigt avahi-daemon keine Bluetooth-Sockets und ich denke, Ihr Webserver auch nicht :-). Geben Sie ihm also keinen Zugriff auf die AF_BLUETOOTH-Adressfamilie. Verwenden Sie einfach die Whitelist AF_INET, AF_INET6 und möglicherweise AF_UNIX
RestrictAddressFamilies=
.Bitte lesen Sie die Dokumentation für jede Option, die Sie verwenden. Einige Optionen sind in Kombination mit anderen Optionen effektiver und einige sind nicht auf allen CPU-Architekturen verfügbar. (Nicht weil die CPU schlecht ist, sondern weil der Linux-Port für diese CPU nicht so gut ausgelegt ist. Ich denke).
(Hier gibt es ein allgemeines Prinzip. Es ist sicherer, wenn Sie Listen schreiben können, was Sie zulassen möchten, und nicht, was Sie ablehnen möchten. Wenn Sie beispielsweise eine Chroot definieren, erhalten Sie eine Liste der Dateien, auf die Sie zugreifen dürfen, und dies ist robuster als zu sagen, dass Sie blockieren möchten
/home
).Grundsätzlich können Sie alle Einschränkungen vor setuid () selbst anwenden. Es ist alles nur Code, den Sie von systemd kopieren können. Die Optionen für Systemeinheiten sollten jedoch wesentlich einfacher zu schreiben sein, und da sie in einem Standardformat vorliegen, sollten sie leichter zu lesen und zu überprüfen sein.
Daher kann ich nur empfehlen, den Sandbox-Abschnitt
man systemd.exec
auf Ihrer Zielplattform zu lesen . Aber wenn Sie die sicherste Ausführung möglich wollen, würde ich keine Angst zu versuchenchroot
(und dann fallenroot
Privilegien) in Ihrem Programm auch . Hier gibt es einen Kompromiss. Durchchroot
die Verwendung werden dem Gesamtdesign einige Einschränkungen auferlegt. Wenn Sie bereits ein Design haben, das Chroot verwendet und das zu tun scheint, was Sie brauchen, klingt das ziemlich gut.quelle
Wenn Sie sich auf systemd verlassen können, ist es in der Tat sicherer (und einfacher!), Das Sandboxing systemd zu überlassen. (Natürlich kann die Anwendung auch erkennen, ob sie von systemd sandboxed gestartet wurde oder nicht, und die Sandbox selbst, wenn sie noch root ist.) Das Äquivalent des von Ihnen beschriebenen Dienstes wäre:
Aber wir müssen hier nicht aufhören. systemd kann auch viele andere Sandbox-Aufgaben für Sie erledigen - hier einige Beispiele:
Siehe
man 5 systemd.exec
für viel mehr Richtlinien und detailliertere Beschreibungen. Wenn Sie Ihren Daemon-Socket aktivierbar machen (man 5 systemd.socket
), können Sie sogar die netzwerkbezogenen Optionen verwenden: Der einzige Link des Dienstes zur Außenwelt ist der von systemd empfangene Netzwerk-Socket, er kann keine Verbindung zu etwas anderem herstellen. Wenn es sich um einen einfachen Server handelt, der nur einige Ports überwacht und keine Verbindung zu anderen Servern herstellen muss, kann dies hilfreich sein. (Die mit dem Dateisystem verbundenen Optionen könnenRootDirectory
meiner Meinung nach auch veraltet sein, sodass Sie möglicherweise nicht mehr die Mühe haben, ein neues Stammverzeichnis mit allen erforderlichen Binärdateien und Bibliotheken einzurichten.)Neuere systemd-Versionen (seit v232) unterstützen ebenfalls
DynamicUser=yes
, wobei systemd den Dienstbenutzer nur für die Laufzeit des Dienstes automatisch für Sie zuweist . Das heißt , Sie müssen nicht einen permanenten Benutzer für den Dienst registrieren lassen , und funktionieren gut , solange der Dienst schreiben nicht an irgendwelche Dateisystem an anderen Stellen als seineStateDirectory
,LogsDirectory
undCacheDirectory
(die man auch in der Unit - Datei deklarieren - sehen Sieman 5 systemd.exec
noch einmal - und welches Systemd sich dann darum kümmert, sie dem dynamischen Benutzer richtig zuzuweisen).quelle