Дейл Хагглунд на місці. Тож я просто хочу сказати те саме, але по-іншому, з деякою специфікою та прикладами. ☺
Правильне в світі 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 для мереж були розроблені для цього спільно. Команди структурно дуже схожі на команди daemontools
UCSPI-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 як суперпользователь, і сервісний процес, який він ікру працює без пільг суперпользователя.