Piszę demona serwera HTTP w C (istnieją powody, dla których), zarządzając nim za pomocą pliku jednostki systemowej.
Piszę na nowo aplikację zaprojektowaną 20 lat temu, około 1995 roku. System, którego używają, to chroot, a następnie setuid, i standardowa procedura.
Teraz w mojej poprzedniej pracy normalną zasadą było to, że nigdy nie uruchamiasz żadnego procesu jako root. Tworzysz dla niego użytkownika / grupę i stamtąd biegasz. Oczywiście system działał jako root, ale moglibyśmy przetwarzać całą logikę biznesową bez rootowania.
Teraz dla demona HTTP mogę uruchomić go bez rootowania, jeśli nie będę chrootował się w aplikacji. Czy nie jest bezpieczniejsze, że aplikacja nigdy nie będzie działać jako root?
Czy nie jest bezpieczniej uruchomić go jako użytkownika mydaemon od samego początku? Zamiast zaczynać od roota, chrootować, a potem konfigurować dla mydaemon-user?
capabilities(7)
.Odpowiedzi:
Wygląda na to, że inni pominęli twój punkt widzenia, co nie było powodem, dla którego warto używać zmienionych korzeni, o czym oczywiście już wiesz, ani co jeszcze możesz zrobić, aby ograniczyć granice demonów, skoro wiesz również o działaniu pod nadzorem nieuprzywilejowane konta użytkowników; ale po co to robić w aplikacji . W rzeczywistości istnieje dość trafny przykład, dlaczego.
Rozważ projekt
httpd
programu dæmon w pakiecie plików publicznych Daniela J. Bernsteina. Pierwszą rzeczą, którą robi, jest zmiana katalogu głównego na katalog główny, którego kazano mu użyć z argumentem polecenia, a następnie upuszczenie uprawnień do nieuprzywilejowanego identyfikatora użytkownika i grupy, które są przekazywane w dwóch zmiennych środowiskowych.Zestawy narzędzi do zarządzania Dæmon mają dedykowane narzędzia do takich rzeczy, jak zmiana katalogu głównego i upuszczanie do nieuprzywilejowanych identyfikatorów użytkowników i grup. Runit Gerrita Pape'a ma
chpst
. Mój zestaw narzędzi Nosh machroot
isetuidgid-fromenv
. Laurent Bercot s6 mas6-chroot
is6-setuidgid
. Wayne Marshall's Perp maruntool
irunuid
. I tak dalej. Rzeczywiście, wszystkie mają własny zestaw narzędzi Daemontools M. Bernsteinasetuidgid
jako poprzednik.Można by pomyśleć, że można wyodrębnić funkcjonalność
httpd
i użyć takich dedykowanych narzędzi. Następnie, jak można sobie wyobrazić, żadna część programu serwera nigdy nie działa z uprawnieniami administratora.Problem polega na tym, że jako bezpośrednia konsekwencja trzeba wykonać znacznie więcej pracy, aby skonfigurować zmieniony katalog główny, a to ujawnia nowe problemy.
W
httpd
obecnej postaci Bernstein jedynymi plikami i katalogami, które znajdują się w drzewie katalogów głównych, są te, które zostaną opublikowane na całym świecie. Na drzewie nie ma nic więcej . Co więcej, nie ma powodu, dla dowolny plik wykonywalny programu obraz istnieć w tym drzewie.Ale przesunąć zmianę katalogu głównego na zewnątrz do programu łańcuch ładowania (lub Systemd) i nagle plik programu obraz
httpd
, wszelkich bibliotek, które ładuje, a jakieś specjalne pliki/etc
,/run
i/dev
że program ładujący lub C Access Runtime library podczas inicjalizacji programu (który może się okazać dość zaskakujące, jeślitruss
/strace
C lub program C ++), również muszą być obecne w zmienionej korzenia. W przeciwnym raziehttpd
nie będzie można połączyć go w łańcuch i nie będzie się ładować / uruchamiać.Pamiętaj, że jest to serwer treści HTTP (S). Może potencjalnie obsłużyć dowolny (czytelny na całym świecie) plik w zmienionym katalogu głównym. Obejmuje to teraz takie rzeczy, jak współdzielone biblioteki, program ładujący program oraz kopie różnych plików konfiguracyjnych modułu ładującego / CRTL dla systemu operacyjnego. A jeśli w jakiś (przypadkowy sposób) sposób serwer zawartości ma dostęp do zapisu , serwer, którego zabezpieczenia zostały naruszone, może uzyskać dostęp do zapisu obrazu programu dla
httpd
siebie, a nawet programu ładującego system. (Pamiętaj, że masz teraz dwa równoległe zestawy/usr
,/lib
,/etc
,/run
, i/dev
katalogi, aby zachować bezpieczny).Nic z tego nie dzieje się, gdy
httpd
same zmiany uprawnień roota i upuszczenia.Wymieniłeś więc niewielką ilość uprzywilejowanego kodu, który jest dość łatwy do skontrolowania i który działa na początku
httpd
programu, działając z uprawnieniami administratora; za znacznie powiększoną powierzchnię ataku plików i katalogów w zmienionym katalogu głównym.Dlatego nie jest to tak proste, jak robienie wszystkiego na zewnątrz programu serwisowego.
Zauważ, że jest to jednak absolutne minimum funkcjonalności
httpd
samej w sobie. Cały kod, który wykonuje takie czynności, jak szukanie w bazie danych kont systemu operacyjnego identyfikatora użytkownika i identyfikatora grupy, aby umieścić je w tych zmiennych środowiskowych w pierwszej kolejności, jest zewnętrzny dlahttpd
programu, w prostych samodzielnych kontrolowanych komendach, takich jakenvuidgid
. (I oczywiście jest to narzędzie ucspi, więc zawiera żadnego kodu, aby nasłuchiwać na danym porcie TCP (-ych) lub do przyjmowania połączeń, te, które są domeną poleceń takich jaktcpserver
,tcp-socket-listen
,tcp-socket-accept
,s6-tcpserver4-socketbinder
,s6-tcpserver4d
, i tak dalej).Dalsza lektura
httpd
. plik publiczny . cr.yp.to.httpd
. Oprogramowanie Daniela J. Bernsteina w jednym . Oprogramowania. Jonathan de Boyne Pollard. 2016 r.gopherd
. Oprogramowanie Daniela J. Bernsteina w jednym . Oprogramowania. Jonathan de Boyne Pollard. 2017 r.źródło
Myślę, że wiele szczegółów twojego pytania może dotyczyć w równym stopniu
avahi-daemon
, na co ostatnio spojrzałem. (Mogłem przeoczyć inny szczegół, który się różni). Uruchamianie demona avahi w chroot ma wiele zalet, na wypadek, gdyby avahi-demon został naruszony. Obejmują one:Punkt 3 może być szczególnie przydatny, gdy nie używasz dbus lub podobnego ... Myślę, że avahi-demon używa dbus, więc zapewnia dostęp do systemu dbus nawet z chroota. Jeśli nie potrzebujesz możliwości wysyłania wiadomości w systemie dbus, odmowa tej możliwości może być całkiem niezłą funkcją bezpieczeństwa.
Zauważ, że jeśli avahi-demon został ponownie napisany, może potencjalnie zdecydować się na systemd dla bezpieczeństwa i użyć np
ProtectHome
. Zaproponowałem zmianę w avahi-demona, aby dodać te zabezpieczenia jako dodatkową warstwę, wraz z kilkoma dodatkowymi zabezpieczeniami, które nie są gwarantowane przez chroot. Możesz zobaczyć pełną listę opcji, które zaproponowałem tutaj:https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a
Wygląda na to, że istnieje więcej ograniczeń, których mógłbym użyć, gdyby avahi-demon nie używał samego chroota, niektóre z nich są wymienione w komunikacie zatwierdzenia. Nie jestem jednak pewien, ile to dotyczy.
Uwaga: zastosowane przeze mnie zabezpieczenia nie ograniczyłyby demona przed otwieraniem plików gniazd UNIX (punkt 3 powyżej).
Innym podejściem byłoby użycie SELinux. Jednak w pewnym sensie wiązałbyś swoją aplikację z tym podzbiorem dystrybucji Linuksa. Powodem, dla którego pomyślałem o SELinux tutaj, jest to, że SELinux w bardzo drobiazgowy sposób ogranicza dostęp procesów przez dbus. Na przykład myślę, że często można się spodziewać,
systemd
że nie będzie na liście nazw autobusów, do których trzeba było wysyłać wiadomości :-).„Zastanawiałem się, czy korzystanie z piaskownicy systemowej jest bezpieczniejsze niż chroot / setuid / umask / ...”
Podsumowanie: dlaczego nie jedno i drugie? Rozszyfrujmy nieco powyższe :-).
Jeśli pomyślisz o punkcie 3, użycie chroot zapewnia większe zamknięcie. ProtectHome = i jego przyjaciele nawet nie starają się być tak restrykcyjni jak chroot. (Na przykład, żadna z nazwanych czarnych list systemowych opcji
/run
, w których zwykle umieszczamy pliki gniazd unix).chroot pokazuje, że ograniczenie dostępu do systemu plików może być bardzo potężne, ale nie wszystko w Linuksie to plik :-). Istnieją systemowe opcje, które mogą ograniczać inne rzeczy, które nie są plikami. Jest to przydatne, jeśli program zostanie przejęty, możesz zmniejszyć dostępne dla niego funkcje jądra, w których może on próbować wykorzystać lukę. Na przykład demon avahi nie potrzebuje gniazd bluetooth i sądzę, że twój serwer sieciowy też nie :-). Nie udzielaj więc dostępu do rodziny adresów AF_BLUETOOTH. Wystarczy dodać do białej listy AF_INET, AF_INET6, a może AF_UNIX, używając tej
RestrictAddressFamilies=
opcji.Przeczytaj dokumentację dotyczącą każdej opcji, której używasz. Niektóre opcje są bardziej skuteczne w połączeniu z innymi, a niektóre nie są dostępne we wszystkich architekturach procesora. (Nie dlatego, że procesor jest zły, ale dlatego, że port Linux dla tego procesora nie był tak ładnie zaprojektowany. Myślę, że).
(Jest tutaj ogólna zasada. Bardziej bezpieczne jest pisanie list tego, na co chcesz zezwolić, a nie tego, czego chcesz odmówić. Na przykład zdefiniowanie chroot daje listę plików, do których masz dostęp, a to jest bardziej niezawodne niż mówienie, że chcesz zablokować
/home
).Zasadniczo możesz zastosować te same ograniczenia przed setuid (). To tylko kod, który można skopiować z systemd. Jednak opcje jednostek systemowych powinny być znacznie łatwiejsze do napisania, a ponieważ są w standardowym formacie, powinny być łatwiejsze do odczytania i przejrzenia.
Dlatego mogę gorąco polecić przeczytanie sekcji piaskownicy
man systemd.exec
na Twojej platformie docelowej. Ale jeśli chcesz, aby możliwie najbardziej bezpieczny projekt, nie bój się próbowaćchroot
(i następnie upuścićroot
przywileje) w programie , jak również . Tu jest kompromis. Używaniechroot
nakłada pewne ograniczenia na ogólny projekt. Jeśli masz już projekt wykorzystujący chroot i wydaje się, że robi to, czego potrzebujesz, to brzmi całkiem nieźle.źródło
Jeśli możesz polegać na systemd, to rzeczywiście bezpieczniej (i prościej!) Jest pozostawić sandboxing systemd. (Oczywiście aplikacja może również wykryć, czy została uruchomiona w trybie piaskownicy przez systemd, czy też sama piaskownica, jeśli nadal jest rootem.) Odpowiednik opisanej usługi to:
Ale nie musimy się na tym kończyć. systemd może również wykonać dla Ciebie wiele innych piaskownic - oto kilka przykładów:
Zobacz
man 5 systemd.exec
o wiele więcej dyrektyw i bardziej szczegółowe opisy. Jeśliman 5 systemd.socket
sprawisz, że demon będzie aktywowany przez gniazdo ( ), możesz nawet użyć opcji związanych z siecią: jedynym łączem usługi do świata zewnętrznego będzie gniazdo sieciowe, które otrzymało od systemd, nie będzie mogło połączyć się z niczym innym. Jeśli jest to prosty serwer, który nasłuchuje tylko na niektórych portach i nie musi się łączyć z innymi serwerami, może to być przydatne. (RootDirectory
Moim zdaniem opcje związane z systemem plików mogą również stać się przestarzałe, więc być może nie musisz już martwić się tworzeniem nowego katalogu głównego ze wszystkimi wymaganymi plikami binarnymi i bibliotekami.)Obsługiwane są także nowsze wersje systemowe (od wersji 232)
DynamicUser=yes
, gdzie systemd automatycznie przydzieli użytkownika usługi tylko dla środowiska wykonawczego usługi. Oznacza to, że nie trzeba się rejestrować stałego użytkownika za usługę, a działa dobrze tak długo, jak służby nie pisać żadnych lokalizacjach systemu plików innych niż jegoStateDirectory
,LogsDirectory
iCacheDirectory
(co można również zadeklarować w pliku jednostki - zobaczman 5 systemd.exec
jeszcze raz - i który system będzie wtedy zarządzał, dbając o prawidłowe przypisanie ich do użytkownika dynamicznego).źródło