Дейл Хэгглунд на месте. Так что я просто собираюсь сказать то же самое, но по-другому, с некоторыми особенностями и примерами. ☺
В мире Unix и Linux правильно сделать следующее:
- иметь небольшую, простую, легко проверяемую программу, которая работает от имени суперпользователя и связывает сокет прослушивания;
- иметь другую маленькую, простую, легко проверяемую программу, которая отбрасывает привилегии, порожденные первой программой;
- чтобы основная часть службы работала в отдельной третьей программе под учетной записью не-суперпользователя и цепью, загруженной второй программой, ожидая просто наследовать дескриптор открытого файла для сокета.
Вы неправильно поняли, где находится высокий риск. Высокий риск заключается в чтении из сети и действии в отношении того, что читается, а не в простых действиях по открытию сокета, привязке его к порту и вызову listen(). Это часть службы, которая осуществляет фактическое общение с высоким риском. Части, которые открываются, bind()и listen(), и даже (в некоторой степени), части accepts(), которые не представляют высокого риска и могут эксплуатироваться под эгидой суперпользователя. Они не используют и не обрабатывают (за исключением IP-адресов источника в данном accept()случае) данные, которые находятся под контролем ненадежных незнакомцев по сети.
Есть много способов сделать это.
inetd
Как говорит Дейл Хагглунд, старый «сетевой суперсервер» inetdделает это. Учетная запись, под которой запускается процесс обслуживания, является одним из столбцов в inetd.conf. Он не разделяет часть прослушивания и часть удаления привилегий на две отдельные программы, маленькие и легко проверяемые, но он разделяет основной код службы на отдельную программу, exec()созданную в процессе службы, который порождается дескриптором открытого файла. для розетки.
Сложность аудита - не такая уж большая проблема, поскольку нужно проверять только одну программу. inetdГлавная проблема не столько в аудите, сколько в том, что он не обеспечивает простого детального управления сервисом во время выполнения по сравнению с более поздними инструментами.
UCSPI-TCP и daemontools
Daniel J. Бернштейна UCSPI-TCP и DaemonTools пакеты были разработаны , чтобы сделать это в совокупности. В качестве альтернативы можно использовать практически эквивалентный набор инструментов Брюса Гюнтера на бис .
Программа для открытия дескриптора файла сокета и привязки к привилегированному локальному порту tcpserver, из UCSPI-TCP. Это делает listen()и accept().
tcpserverзатем порождает либо служебную программу, которая сама отбрасывает привилегии root (поскольку обслуживаемый протокол включает в себя запуск от имени суперпользователя, а затем «вход в систему», как в случае, например, с FTP или демоном SSH), или setuidgidкоторый является Самодостаточная небольшая и легко проверяемая программа, которая только отбрасывает привилегии и затем загружает их по цепочке в собственно сервисную программу (ни одна часть которой, таким образом, никогда не работает с привилегиями суперпользователя, как, например, в случае с qmail-smtpd).
runСценарий службы , таким образом, будет, например, (этот для dummyidentd для предоставления нулевой услуги IDENT):
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
перекус
Мой пакет Nosh предназначен для этого. У него есть небольшая setuidgidутилита, как и у других. Небольшое отличие состоит в том, что его можно использовать со systemdслужбами -style "LISTEN_FDS", а также со службами UCSPI-TCP, поэтому традиционная tcpserverпрограмма заменяется двумя отдельными программами: tcp-socket-listenи tcp-socket-accept.
Опять же, целевые утилиты порождают и загружают друг друга. Одна интересная особенность дизайна заключается в том, что можно отказаться от привилегий суперпользователя после, listen()но даже раньше accept(). Вот runсценарий, qmail-smtpdкоторый действительно делает именно это:
#!/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 \
'
Программы , которые работают под эгидой суперпользователя являются небольшими инструментами цепи нагрузки сервиса-агностиком fdmove, clearenv, envdir, softlimit, tcp-socket-listen, и setuidgid. К моменту shзапуска сокет открыт и привязан к smtpпорту, и у процесса больше нет привилегий суперпользователя.
S6, S6-сети и Execline
Пакеты Laurent Bercot для сетей s6 и s6 были разработаны для того, чтобы сделать это совместно. Команды структурно очень похожи на команды daemontoolsUCSPI-TCP.
runсценарии были бы почти такими же, за исключением замены s6-tcpserverдля tcpserverи s6-setuidgidдля setuidgid. Тем не менее, можно также использовать набор инструментов execline М. Bercot в то же время.
Вот пример службы FTP, слегка модифицированной по сравнению с оригиналом Уэйна Маршалла , которая использует execline, s6, s6-network и программу сервера FTP из publicfile :
#!/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 - это еще один набор инструментов, который работает по тем же принципам, что и ucspi-tcp и s6-network. Инструменты есть chpstи на tcpsvdэтот раз, но они делают то же самое, и код высокого риска, который выполняет чтение, обработку и запись вещей, отправленных по сети ненадежными клиентами, все еще находится в отдельной программе.
Вот пример работы М. Пейпаfnord в runсценарии:
#!/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новая система контроля и инициализации сервиса, которую можно найти в некоторых дистрибутивах Linux, предназначена для того, что inetdможет делать . Тем не менее, он не использует набор небольших автономных программ. К systemdсожалению, нужно проводить аудит полностью.
С помощью systemdодного создает файлы конфигурации, чтобы определить сокет, который systemdпрослушивает, и сервис, который systemdзапускается. Файл «единицы измерения» службы имеет настройки, которые позволяют значительно контролировать процесс обслуживания, в том числе, от имени какого пользователя он запускается.
С этим пользователем, установленным как не суперпользователь, он systemdвыполняет всю работу по открытию сокета, привязке его к порту и вызову listen()(и, если требуется, accept()) в процессе # 1 в качестве суперпользователя и в сервисном процессе, который он порождения запускаются без привилегий суперпользователя.