Дейл Хагглунд на місці. Тож я просто хочу сказати те саме, але по-іншому, з деякою специфікою та прикладами. ☺
Правильне в світі Unix та Linux:
- мати невелику, просту, легко піддається аудиту програму, яка працює як суперпользователь і зв'язує розетку прослуховування;
- мати ще одну невелику, просту, легко піддається аудиту програму, яка скасовує привілеї, породжену першою програмою;
- щоб м'ясо сервісу в окремій третій програмі працювало під непідрядним обліковим записом і ланцюгом, завантаженим другою програмою, очікуючи просто успадкувати відкритий дескриптор файлу для сокета.
У вас неправильне уявлення про те, де високий ризик. Високий ризик полягає у читанні з мережі та дії на прочитане не в простих актах відкриття сокета, прив'язки до порту та виклику listen(). Це частина сервісу, яка здійснює фактичну комунікацію, яка становить високий ризик. Частини, які відкриваються, bind()і listen(), і навіть (в деякій мірі) частина, що accepts()не є великим ризиком і можуть бути запущені під егідою суперрусера. Вони не використовують і не діють на (за винятком вихідних IP-адрес у accept()випадку) даних, які знаходяться під контролем недовірених незнайомих людей по мережі.
Існує багато способів зробити це.
inetd
Як каже Дейл Хагглунд, старий "мережевий суперсервер" inetdробить це. Обліковий запис, під яким запускається сервісний процес, є одним із стовпців в inetd.conf. Він не розділяє прослуховувальну частину та частину привілеїв, що випадають, на дві окремі програми, невелику і легко піддається аудиту, але він відокремлює основний код послуги на окрему програму, exec()редагувану в процесі обслуговування, який породжується дескриптором відкритого файлу для розетки.
Складність аудиту не є великою проблемою, оскільки потрібно лише перевірити одну програму. inetdОсновна проблема полягає не в тому, щоб зробити аудит настільки великим, але він полягає в тому, що він не забезпечує простий дрібнозернистий сервіс контролю часу виконання, порівняно з останніми інструментами.
UCSPI-TCP і демон
Пакети 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
ніш
Мій пакет з нішами призначений для цього. Він має невелику 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 М. Беркота .
Ось приклад послуги FTP, злегка модифікованої з оригіналу Wayne Marshall , яка використовує execline, s6, s6-мережу та програму сервера 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
Gerrit Папа ipsvd ще один набір інструментів , який проходить по тій же схемі, UCSPI-ТСР і s6-мереж. Інструменти є 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, нова система нагляду та обслуговування init, яку можна знайти в деяких дистрибутивах Linux, покликана робити все, що inetdможе зробити . Однак він не використовує набір невеликих автономних програм. На systemdжаль, доводиться проводити аудит у повному обсязі.
За допомогою systemdодного створюються файли конфігурації для визначення сокету, який systemdслухає, і служби, яка systemdзапускається. У файлі "блок" служби є налаштування, які дозволяють здійснювати великий контроль над процесом обслуговування, включаючи того, якого користувача він працює.
Якщо цей користувач налаштований як непідрядник, systemdвиконує всю роботу над відкриттям сокета, прив'язкою його до порту та викликом listen()(і, якщо потрібно accept()), в процесі №1 як суперпользователь, і сервісний процес, який він ікру працює без пільг суперпользователя.