Я установил возможности Linux , чтобы обеспечивать работу серверных служб по принципу минимальных полномочий и, таким образом, предоставлять только абсолютно необходимые частичные права. Таким образом, я сокращаю Атакующая поверхность заметно, не блокируя функции.
Центральные пункты
- Наименьшие привилегии Последовательно: службы получают только те функции, которые им действительно необходимы.
- Мелкозернистый Вместо прав root: около 40–50 возможностей заменяют полный доступ.
- Разделение процессов: разделение привилегий снижает ущерб при эксплуатации уязвимостей.
- Файл Возможности: привязка прав непосредственно к двоичным файлам.
- Поддается аудиту: Команда getcap позволяет получить четкое представление о специальных правах.
Почему получение прав root сопряжено с риском — и как Capabilities меняют ситуацию
Раньше почти все серверные службы работали с Коренные права, что в случае взлома могло сразу привести к полному захвату системы. Сегодня я целенаправленно распределяю права, используя такие возможности, как CAP_NET_BIND_SERVICE для портов ниже 1024 и лишить все остальные расширенных прав. Таким образом, веб-сервер сможет привязываться к портам, но не сможет загружать модули ядра или изменять владельцев файлов, что Безопасность значительно повышает. Четкое разделение задач снижает эффективность атак, поскольку уязвимый процесс может выполнять лишь ограниченный набор действий. Те, кто хочет придать этой концепции более четкую структуру, могут очень точно настроить права разбить на мелкие части и таким образом систематически ограничивать критически важные операции. Таким образом, монолитный корневой сервис превращается в набор сервисов с минимальными, четко определёнными полномочиями.
Как работают наборы возможностей в ядре
Каждый процесс имеет несколько Наборы возможностей, которые ядро проверяет при выполнении чувствительных действий. Набор «Effective-Set» определяет, что процесс может делать прямо сейчас, тогда как набор «Permitted-Set» содержит пул возможных прав. С помощью набора «Inheritable-Set» я могу контролировать, что при execve() передаются дочерним процессам, что особенно важно в случае оберток и стартовых скриптов. Bounding-Set определяет жесткий верхний предел, благодаря чему определённые возможности больше никогда не могут быть получены, даже в случае сбоев в приложении. С помощью Ambient-Set я передаю возможности без SUID обычным программам и сохраняю Маршрут атаки небольшие. В совокупности эти наборы позволяют мне осуществлять очень точную регулировку, которая значительно выходит за рамки классического принципа «всё или ничего», характерного для UID 0.
| Набор | Назначение | Типичное использование | Риск неправильной конфигурации |
|---|---|---|---|
| Эффективный | Навыки, действующие сейчас | Проверка каждой привилегированной операции | Процесс может сразу же привести к перегрузке |
| Разрешено | Набор разрешенных навыков | Источник данных для «Effective-Set» | Ненужные резервы остаются в распоряжении |
| Наследуемое | Наследуемые способности | Контролируемая передача при вызове execve() | Дети наследуют права без необходимости |
| Ограничение | Верхний предел всех прав | Определение постоянных исключений | Возможно восстановление широких прав |
| Эмбиент | Передача без SUID | Обычные программы получают возможности | Более широкое и незаметное предоставление прав |
На практике важны два дополнительных аспекта: во-первых, решающим фактором является Securebits о том, запускается ли процесс после смены идентификатора пользователя (например, посредством setuid()) сохраняет свои возможности. С помощью PR_SET_KEEPCAPS это можно целенаправленно контролировать — типичный алгоритм действий: кратковременно запуститься с правами root, создать необходимые сокеты или ресурсы, переключиться на UID непривилегированного пользователя и сохранить только необходимые возможности. Во-вторых, следует учитывать, что это Ограничивающее множество окончательно включено в текущую цепочку процессов. Если на раннем этапе в стартовом пути удалить ненужные возможности, то впоследствии даже в результате неправильной настройки больше не удастся получить „запрещенные“ права.
Управление правами доступа к файлам с помощью File Capabilities
Вместо разовой услуги — постоянная Особые права Чтобы это учесть, я предпочитаю привязывать их напрямую к двоичному файлу. Через setcap cap_net_bind_service=+eip /usr/bin/node я разрешаю привязку портов без необходимости запуска процесса с правами root. С помощью getcap /usr/bin/node или рекурсивно getcap -r / 2>/dev/null Я проверяю распределение и сохраняю контроль. Удаление осуществляется через setcap -r /путь/к/бинарному_файлу, поэтому после завершения задачи я отзываю временные права. При копировании возможности часто теряются, поэтому я явно сохраняю их при развертывании, чтобы регрессии чтобы этого избежать. Таким образом, сборки остаются воспроизводимыми, а права всегда четко документируются.
Возможности файлов реализуются в виде расширенных атрибутов (security.capability) в файловой системе. Для этого требуется подходящая файловая система и соответствующие параметры монтирования. Такие инструменты, как tar и rsync необходимо явно указать XAttrs (например,. tar --xattrs, rsync -XA), иначе права будут незаметно удалены. Менеджеры пакетов могут устанавливать возможности на этапах после установки; я предпочитаю фиксировать это в процессе сборки/релиза, чтобы избежать неожиданностей при обновлениях. Кроме того, важно учитывать: скрипты интерпретатора (например, с shebang) не наследуют файловые возможности, в отличие от ELF-бинарников. Мощные возможности на переводчик Устанавливать это и так рискованно — я предпочитаю разделить компоненты и работать с небольшими специализированными вспомогательными бинарными файлами.
Принцип минимальности для серверных служб на практике
Я запускаю веб-сервер от имени пользователя без привилегий и предоставляю исключительно CAP_NET_BIND_SERVICE, чтобы процесс мог привязаться к порту 80/443 и не создавал дополнительных Привилегии . Управление файлами и каталогами я продолжаю осуществлять с помощью прав доступа POSIX, а также, по желанию, с помощью профилей MAC, благодаря чему конфигурация и содержимое остаются защищенными отдельно друг от друга. Агенты мониторинга или ведения журналов получают ограниченные сетевые права и права на чтение журналов, но не имеют никаких полномочий на внесение изменений в систему. В контейнерных средах я дополнительно сокращаю набор возможностей и сочетаю его с фильтрами системных вызовов, чтобы строго ограничить поведение. Такое сочетание снижает последствия успешных эксплойтов и повышает Прозрачность фактических полномочий. Службы продолжают функционировать, однако пространство для маневра остается ограниченным.
Вместо того чтобы назначать права доступа (Capabilities), я иногда полностью их исключаю: активация сокета предоставляет привилегированные прослушиватели (например, 443/tcp) через процесс Init и передает службе только открытый дескриптор файла. В этом случае процессу приложения не требуется CAP_NET_BIND_SERVICE и т. д. Кроме того, разовые действия с правами root (например, создание каталога PID) можно выполнить заранее, а затем последовательно отказаться от этих прав. Чем меньше прав вообще чем больше их в игре, тем устойчивее система к цепным ошибкам.
Правильная реализация принципа разделения привилегий
Я разбиваю обширные сервисы на несколько Подпроцессы, каждый из которых обладает только необходимыми возможностями. Фронтенд-процесс устанавливает соединение по протоколу TLS и привязывается к портам, но не имеет прав доступа к файловой системе для внесения критически важных изменений. Бэкенд-процесс обрабатывает данные внутренне, имеет минимальные права на чтение конфигурации и взаимодействует с базами данных без собственных сетевых возможностей. Административные задачи, такие как ротация логов или техническое обслуживание, выполняются с помощью специальных инструментов с ограниченными по времени возможностями. Если злоумышленник атакует одну из частей, остальная часть системы остаётся незатронутой, поскольку Разрешения определены достаточно узко. Таким образом, безопасность зависит от структуры приложения, а не от всемогущих системных прав.
Для такой разбивки целесообразно использовать четкую оркестрацию запуска. В классических конфигурациях этим занимается супервизор; в современных системах я предпочитаю использовать systemd, поскольку он напрямую интегрирует возможности (capabilities), cgroups и пространства имён (namespaces). Таким образом, я могу запускать сетевой фронтенд, рабочие процессы и инструменты администрирования в отдельных песочницах, ограничивать ресурсы и настраивать автоматический перезапуск в случае сбоя — при этом никогда не предоставляя права root всем и каждому.
Объединение средств безопасности: POSIX, MAC и возможности
Возможности работают лучше всего, если я использую их вместе с классическими Права доступа к файлам и системах MAC. SELinux или AppArmor могут дополнительно ограничивать действия, несмотря на присвоенные возможности, создавая таким образом многоуровневую защиту. Так, процесс может привязываться к порту, но политика запрещает ему читать конфиденциальные файлы. Те, кто хочет глубже изучить различия между этими подходами, найдут наглядное сравнение в SELinux против AppArmor и затем может выбрать подходящую стратегию защиты. В результате формируется комплексная система защиты, которая сдерживает атаки на нескольких уровнях и Атакующая поверхность еще больше сокращается. Таким образом, предоставление прав остается поддающимся проверке, воспроизводимым и последовательным.
Ситуация становится особенно сложной, когда я, кроме того, NoNewPrivileges Включить: в этом случае процессы и дочерние процессы не смогут получить новые привилегии (например, через SUID или вновь установленные возможности файлов). В сочетании с жестким списком ограничений возможностей это создает барьер безопасности, который предотвращает последующее расширение привилегий даже при некорректной настройке.
Надежное распределение и аудит возможностей
Я считаю, что выделенный Набор способностей как можно меньше и избегайте всего, что звучит как „второй root“, например CAP_SYS_ADMIN. Интерпретаторы, такие как Python, Perl или оболочки, не получают мощных возможностей, поскольку их функционал легко может быть использован не по назначению. Благодаря регулярным проверкам посредством getcap -r / 2>/dev/null я выявляю аномалии и устраняю их. Двоичные файлы с правами доступа (capabilities) защищены от записи, принадлежат пользователю root и не находятся в путях, которые могут изменять обычные пользователи. Кроме того, перед каждым выпуском я проверяю собственные бинарные файлы и документирую изменения, чтобы Обзор и воспроизведение будут происходить надежно. Таким образом, процесс предоставления прав останется под контролем, а внесенные изменения — прозрачными.
Во время выполнения я проверяю процессы с помощью /proc//status (Поля CapEff, CapPrm, CapInh). Это позволяет получить шестнадцатеричные значения активных наборов и сразу же определить, превышает ли приложение предусмотренные возможности. Такие инструменты, как capsh --print или getpcaps облегчают отладку. С помощью подсистемы Linux Audit я дополнительно регистрирую изменения в возможностях (capabilities) или в security.capability-атрибуты файлов для отслеживания манипуляций. Если рассматривать возможности (Capabilities) как объект конфигурации и тщательно проверять изменения, это обеспечит воспроизводимость аудитов и упростит подтверждение соответствия требованиям.
Частые препятствия и как их избежать
Типичная ловушка: при копировании Атрибуты теряются, в результате чего службы внезапно перестают запускаться или, наоборот, ограничения становятся недостаточными. Поэтому я явно фиксирую возможности в сборке или назначаю их автоматически на этапе после установки. Еще одной ошибкой является чрезмерное использование универсальных возможностей, которые открывают больше, чем необходимо. Лучше использовать конкретные возможности, такие как CAP_NET_RAW или CAP_CHOWN использовать их только там, где они действительно выполняют какую-то функцию. Набор «Ambient» я тоже использую сдержанно, чтобы не возникло нежелательных Передача распространяются. Целенаправленное сокращение и регулярная проверка позволяют предотвратить уязвимости, возникающие из-за ошибок при эксплуатации.
Также важно: систематически удалять бинарные файлы с правами SUID. Там, где раньше требовались права SUID (например, для отправки ICMP), часто можно обойтись с помощью CAP_NET_RAW работать — или, что ещё лучше, вынести эту функцию в минимально возможный вспомогательный процесс с очень чётко определёнными задачами. Кроме того, я стараюсь не размещать Capabilities во временно существующих или доступных для записи пользователями путях. Строгий режим владения и развертывания (Root:root, 0755/0555, неизменяемые пути) предотвращает „потерю“ прав из-за замены бинарных файлов.
Возможности контейнерных технологий и DevSecOps
В контейнерных средах я сокращаю Возможности агрессивно и удаляю всё, что не является обязательным для данной рабочей нагрузки. Кроме того, я создаю Профиль Seccomp которая блокирует рискованные системные вызовы и тем самым создает дополнительный барьер. В конвейерах сборки я декларативно определяю возможности, тестирую их в тестовой среде и фиксирую с указанием версии. Это благоприятно сказывается на обеспечении соответствия требованиям, поскольку я могу подтвердить соблюдение принципа «минимальных привилегий» и беспрерывно документировать изменения прав доступа. Таким образом, контейнеры остаются строго контролируемыми, что не мешает выполнению их задач, а Атакующая поверхность остаётся небольшим. В сочетании с образами, содержащими только самое необходимое, уровень безопасности дополнительно повышается.
Важно в контексте контейнеров: возможности находятся в пространствах имён Относительно. В пределах одного пользовательского пространства имён процесс может иметь права „Root“, однако его возможности распространяются только на соответствующие пространства имён — это значительно сужает зону воздействия. В свою очередь, „--с привилегиями“Практически всегда запрещено: это отключает жесткие ограничительные границы и открывает гораздо больше, чем нужно. Поэтому я по умолчанию запускаю контейнеры с настройкой „все удалить, добавлять по мере необходимости“ и дополняю NoNewPrivileges, ограничения cgroup и монтирование в режиме «только для чтения». Для сервисов, которым нужно только прослушивать, я использую активацию через сокеты или сайдкары, чтобы обойтись совсем без дополнительных возможностей.
Пример использования systemd: декларативное ограничение возможностей
В сервисных блоках я определяю, что процесс может делать в пределах максимально допустимого — четко, повторяемо и с возможностью контроля версий. Краткий пример веб-сервиса, который может подключаться только к порту 443 и в остальном подвергается значительным ограничениям:
[Unit]
Description=Минимальный веб-сервис без прав root
[Service]
User=web
Group=web
ExecStart=/usr/bin/my-web
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/my-web
RestrictAddressFamilies=AF_INET AF_INET6
SystemCallFilter=@basic-io @network-io
LockPersonality=yes
MemoryDenyWriteExecute=yes
[Install]
WantedBy=multi-user.target
Сочетание Возможности окружающей среды и жесткой CapabilityBoundingSet обеспечивает, чтобы служба получала только необходимые полномочия и ничего лишнего. NoNewPrivileges предотвращает последующее повышение привилегий, ProtectSystem и ReadWritePaths регулируют доступ на запись, а строгий фильтр системных вызовов предотвращает ненужные точки входа в ядро.
Часто используемые функции — и безопасные альтернативы
- CAP_NET_BIND_SERVICE: Привязка к портам <1024. Альтернатива: активация сокетов, размещение обратного прокси перед сервером.
- CAP_NET_RAW: Сырые сокеты (Ping, DHCP). Альтернатива: небольшой вспомогательный процесс вместо широких прав интерпретатора.
- CAP_CHOWN/CAP_FOWNER: Настройки владельца/ACL. Альтернатива: готовые каталоги, специальные инструменты для обслуживания.
- CAP_SYS_PTRACE: Отладка/трассировка — только в тестовой среде, никогда не применяется повсеместно в производственной среде.
- CAP_SYS_ADMIN: „Второй root“ — следует избегать; нужно конкретизировать, что действительно необходимо.
Я всегда выбираю минимальный набор прав, необходимый для точного включения требуемой функции. Если какая-либо возможность открывает несколько путей для атак (например, RAW-сокеты), я изолирую эту функцию в отдельном кратковременном процессе и после завершения работы снова отзываю права.
Практический контрольный список для обеспечения надежных возможностей
- Запускается ли служба без прав root? Если нет, то почему — и можно ли решить эту проблему с помощью активации сокетов или небольших вспомогательных бинарных файлов?
- Это все Доказано ли, что присвоенные возможности действительно необходимы (подтверждение функциональности, тестовые случаи)?
- Определено ли ограничивающее множество максимально узко и на раннем этапе?
- Сохраняется ли согласованность XAttrs при сборке, развертывании и резервном копировании (флаги rsync/tar, скрипты пакетов)?
- Следует ли мне последовательно отказываться от использования возможностей (Capabilities) в интерпретаторах и бинарных файлах с правами SUID?
- Защищены ли права владельца и права доступа к файлам (Root:root, 0755/0555), а также пути от несанкционированного изменения?
- Действуют ли дополнительные меры контроля (NoNewPrivileges, Seccomp, профили MAC)?
- Проводится ли аудит технологических возможностей во время выполнения (
/proc//status, getpcaps) и были ли задокументированы изменения? - Настроены ли контейнеры по умолчанию с параметром „drop all, add minimal“ и без параметра „privileged“?
Краткое резюме
Linux Функции «Capabilities» разбивают классические права root на небольшие, управляемые единицы и тем самым обеспечивают технически корректную реализацию принципа минимальных прав. Я назначаю службам только те возможности, которые им действительно нужны, и сочетаю это с правами POSIX, а также политиками MAC. Файловые возможности (File Capabilities) гарантируют, что права напрямую привязаны к бинарным файлам, а аудит чётко показывает, кто и что может делать. Благодаря разделению привилегий, ограниченным правам контейнеров и фильтрам системных вызовов я минимизирую ущерб в случае эксплуатации уязвимости. Регулярные проверки, строгие права владения и записи, а также документированный процесс выпуска облегчают процесс предоставления прав. Таким образом, серверная служба остается работоспособной, но Место для маневра для злоумышленников постоянно сводится к минимуму.


