Dale Hagglund jest na miejscu. Więc powiem to samo, ale w inny sposób, z pewnymi szczegółami i przykładami. ☺
W światach Uniksa i Linuksa właściwą rzeczą jest:
- mieć mały, prosty, łatwo kontrolowany program, który działa jako superużytkownik i wiąże gniazdo nasłuchujące;
- mieć inny mały, prosty, łatwy do skontrolowania program, który odrzuca uprawnienia, spawnowany przez pierwszy program;
- aby mięso usługi, w osobnym trzecim programie, działało pod kontem nieużytkownika i łańcuchem ładowanym przez drugi program, oczekując po prostu odziedziczenia otwartego deskryptora pliku dla gniazda.
Nie masz pojęcia, gdzie jest wysokie ryzyko. Wysokie ryzyko polega na czytaniu z sieci i działaniu na podstawie tego, co nie jest odczytywane w prostych czynnościach otwierania gniazda, wiązania go z portem i wywoływania listen()
. Jest to część usługi, która faktycznie komunikuje się, co jest dużym ryzykiem. Części, które otwarty, bind()
i listen()
, a nawet (do pewnego stopnia) część, która accepts()
, nie są wysokie ryzyko i może być prowadzony pod egidą administratora. Nie używają i nie działają na danych (z wyjątkiem źródłowych adresów IP w accept()
przypadku) danych, które są pod kontrolą niezaufanych nieznajomych w sieci.
Można to zrobić na wiele sposobów.
inetd
Jak mówi Dale Hagglund, inetd
robi to stary „superserver sieciowy” . Konto, na którym jest uruchamiany proces obsługi, jest jedną z kolumn w inetd.conf
. Nie dzieli części nasłuchującej i upuszczania części na dwa osobne programy, małe i łatwe do skontrolowania, ale dzieli główny kod usługi na osobny program, exec()
edytowany w procesie serwisowym, który spawnuje z otwartym deskryptorem pliku dla gniazda.
Trudność audytu nie stanowi większego problemu, ponieważ wystarczy skontrolować tylko jeden program. inetd
Głównym problemem nie jest zbyt wiele inspekcji, ale raczej to, że nie zapewnia prostej, precyzyjnej kontroli usług środowiska wykonawczego w porównaniu z nowszymi narzędziami.
UCSPI-TCP i daemontools
Pakiety UCSPI-TCP i daemontools Daniela J. Bernsteina zostały zaprojektowane w tym celu w połączeniu. Alternatywnie można użyć w dużej mierze równoważnego zestawu narzędzi do bisów Daemontools Bruce'a Guentera .
Program do otwierania deskryptora pliku gniazda i łączenia się z uprzywilejowanym portem lokalnym pochodzi tcpserver
z UCSPI-TCP. Robi zarówno listen()
i accept()
.
tcpserver
następnie spawnuje albo program usługowy, który sam upuszcza uprawnienia roota (ponieważ obsługiwany protokół wymaga uruchomienia jako superużytkownik, a następnie „zalogowania się”, jak ma to miejsce na przykład w przypadku demona FTP lub SSH) lub setuidgid
który jest samodzielny mały i łatwy do skontrolowania program, który jedynie upuszcza uprawnienia, a następnie łączy obciążenia z odpowiednim programem serwisowym (z którego żadna część nigdy nie działa z uprawnieniami administratora, jak ma to miejsce, powiedzmy, qmail-smtpd
).
run
Skrypt usługi byłby więc na przykład (ten dla dummyidentd zapewniający zerową usługę IDENT):
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
nosh
Mój pakiet nosh jest do tego przeznaczony. Ma małą setuidgid
użyteczność, podobnie jak inne. Jedyną niewielką różnicą jest to, że można go używać z systemd
usługami typu „LISTEN_FDS”, a także z usługami UCSPI-TCP, więc tradycyjny tcpserver
program został zastąpiony przez dwa osobne programy: tcp-socket-listen
i tcp-socket-accept
.
Ponownie, narzędzia jednocelowe odradzają się i ładują się nawzajem. Jednym z interesujących elementów tego projektu jest to, że można zrezygnować z uprawnień administratora po, listen()
ale nawet wcześniej accept()
. Oto run
skrypt, qmail-smtpd
który naprawdę robi dokładnie to:
#!/bin/nosh
fdmove -c 2 1
clearenv --keep-path --keep-locale
envdir env/
softlimit -m 70000000
tcp-socket-listen --combine4and6 --backlog 2 ::0 smtp
setuidgid qmaild
sh -c 'exec \
tcp-socket-accept -v -l "${LOCAL:-0}" -c "${MAXSMTPD:-1}" \
ucspi-socket-rules-check \
qmail-smtpd \
'
Programy, które działają pod egidą administratora są drobne narzędzia chain-loading service-agnostyk fdmove
, clearenv
, envdir
, softlimit
, tcp-socket-listen
, i setuidgid
. Do momentu sh
uruchomienia gniazdo jest otwarte i powiązane z smtp
portem, a proces nie ma już uprawnień administratora.
s6, s6-networking i execline
Pakiety sieciowe Laurent Bercot s6 i s6 zostały zaprojektowane do tego w połączeniu. Polecenia są strukturalnie bardzo podobne do poleceń daemontools
i UCSPI-TCP.
run
skrypty byłyby prawie takie same, z wyjątkiem podstawienia na s6-tcpserver
for tcpserver
i s6-setuidgid
for setuidgid
. Jednakże, można również zdecydować się na korzystanie z M. Bercot za execline zestawu narzędzi jednocześnie.
Oto przykład usługi FTP, lekko zmodyfikowanej w stosunku do oryginału Wayne'a Marshalla , która wykorzystuje execline, s6, s6-networking i program serwera FTP z pliku publicznego :
#!/command/execlineb -PW
multisubstitute {
define CONLIMIT 41
define FTP_ARCHIVE "/var/public/ftp"
}
fdmove -c 2 1
s6-envuidgid pubftp
s6-softlimit -o25 -d250000
s6-tcpserver -vDRH -l0 -b50 -c ${CONLIMIT} -B '220 Features: a p .' 0 21
ftpd ${FTP_ARCHIVE}
ipsvd
Ipsvd Gerrit Pape to kolejny zestaw narzędzi, który działa na tych samych zasadach, co ucspi-tcp i s6-networking. Narzędzia są chpst
i tcpsvd
tym razem, ale robią to samo, a kod wysokiego ryzyka, który odczytuje, przetwarza i zapisuje rzeczy wysyłane przez sieć przez niezaufanych klientów, nadal znajduje się w osobnym programie.
Oto przykład działania M. Pape'afnord
w run
skrypcie:
#!/bin/sh
exec 2>&1
cd /public/10.0.5.4
exec \
chpst -m300000 -Uwwwuser \
tcpsvd -v 10.0.5.4 443 sslio -v -unobody -//etc/fnord/jail -C./cert.pem \
fnord
systemd
systemd
, nowy system nadzoru usług i inicjalizacji, który można znaleźć w niektórych dystrybucjach Linuksa, ma na celu robienie tego, co inetd
można . Jednak nie używa pakietu małych samodzielnych programów. systemd
Niestety, należy przeprowadzić audyt w całości.
Z systemd
jednym tworzy pliki konfiguracyjne, aby określić, które gniazdo systemd
nasłuchuje i usługi, które systemd
rozpoczyna. Plik „jednostki” usługi ma ustawienia, które pozwalają na dużą kontrolę nad procesem obsługi, w tym nad tym, jak użytkownik działa.
Gdy ten użytkownik jest ustawiony jako użytkownik niebędący superużytkownikiem, systemd
wykonuje całą pracę polegającą na otwarciu gniazda, powiązaniu go z portem i wywołaniu listen()
(oraz, w razie potrzeby, accept()
) w procesie nr 1 jako superużytkownik oraz procesie obsługi spawn działa bez uprawnień administratora.