Безопасность встраиваемых систем Linux ч.2
Разрешения
Один из способов уменьшить ущерб при эксплуатации уязвимости — не запускать программы с привилегиями root (суперпользователя)! Вы должны воспользоваться системой разграничения прав доступа и запускать процессы от имени непривилегированных пользователей, которые должны быть добавлены в группы с доступом только к тем ресурсам, которые необходимы для запуска.
Это называется принципом набора минимальных привилегий и является одним из правил разработки безопасных систем. Приложения должны запускаться только с теми привилегиями, которые необходимы для выполнения своей работы.
Но проблема заключается в том, что в Linux для выполнения некоторых привилегированных операций (например, настройка времени, использование RAW сокетов и т. д.) требуются права «root пользователя». В этом случае потребуется запустить программу от имени root, но это неправильный подход. Один из способов решить эту проблему использовать гранулированные права доступа, в Linux это называется — capabilities.
Гранулированные права доступа (Linux capabilities)
Гранулированные права доступа (Linux capabilities) — это детализированная система контроля доступа для процессов, выполняемых с привилегиями root.
Ядро Linux делит привилегии связанные с суперпользователем на отдельные единицы, известные как capabilities, которые могут быть независимо включены или отключены. Идея состоит в том, что программа будет работать от имени пользователя root, но при этом будет включать только те capabilities, которые необходимы для выполнения своей работы. В Linux для перечисления capabilities, которые требуются для запуска конкретной программе, используется инструмент — getcap:
$ getcap /usr/bin/ping /usr/bin/ping = cap_net_raw+ep
Предоставление процессу определенных гранулированных прав от пользователя root, может быть весьма избыточным, поэтому следует еще больше минимизировать набор выдаваемых прав с на основе мандатного управления доступом.
Мандатное управление доступом
Linux традиционно поддерживает Дискреционное управление доступом (Discretionary Access Control, DAC). DAC — управление доступом субъектов к объектам на основе списков управления доступом или матрицы доступа. Субъект с определенным правом доступа может передать это право любому другому субъекту. Например, когда вы расписываете доступ к файлу, вы указываете: имя владельца файла (субъект), права на чтение, права на запись, права на запуск, для субъектов: пользователь или программа выполняющаяся под именем пользователя. Объектами права выступают: файлы, каталоги, и т.д.
![](https://habrastorage.org/webt/z9/ci/s2/z9cis28lmbk7n0ar-p7mgalylkm.png)
Дискреционное управление доступом
Пример дискреционного управления доступом к файлам в Linux Ubuntu:
root@bananapim64:/# ls -l total 72 drwxr-xr-x 2 root root 4096 May 12 22:11 bin drwxr-xr-x 3 root root 4096 Jun 2 16:53 boot drwxr-xr-x 16 root root 3660 May 30 01:08 dev drwxr-xr-x 94 root root 4096 May 30 01:08 etc drwxr-xr-x 3 root root 4096 Feb 4 11:33 home drwxr-xr-x 16 root root 4096 May 13 21:36 lib drwx------ 2 root root 16384 Feb 4 11:33 lost+found ...
Другой тип контроля доступа называется Мандатное управление доступом (Mandatory access control, MAC). MAC — разграничение доступа субъектов к объектам, основанное на назначении метки (мандата) конфиденциальности для информации, содержащейся в объектах, и выдаче официальных разрешений (допуска) субъектам на обращение к информации такого уровня конфиденциальности.
![](https://habrastorage.org/webt/oc/eo/zq/oceozqwqwacdyj8gg3l8x2a5pkg.png)
Мандатное управление доступом
Модель MAC реализована в ядре Linux на основе фреймворка — Linux Security Module (LSM). LSM — структура, которая позволяет ядру Linux поддерживать различные модели компьютерной безопасности. Двумя наиболее известными модулями безопасности в Linux, реализующими MAC, являются SELinux и AppArmor:
- SELinux — одна из самых популярных (и сложных) реализаций MAC, первоначально была разработана NSA, сегодня используется в Android и Fedora.
- AppArmor — также является популярной и более дружественной реализацией MAC, поддерживается фондом Canonical и используемой в дистрибутивах Linux, таких как Ubuntu и Debian.
Но иногда использование MAC недостаточно для защиты системы от уязвимого приложения. В этом случае обеспечить должную защиту поможет запуск приложения в песочнице.
Песочница для приложений
Песочница позволяет изолировать приложения от основной системы. Самый старый механизм реализации песочницы в Linux это — chroot. Но chroot позволяет изолировать только файловую систему, что не обеспечивает полную изоляцию приложения от системы. Можно использовать аппаратную виртуализацию для каждого приложения, но этот подход очень требователем к аппаратным ресурсам и не подходит для встраиваемых система. В настоящее время существует два решения для запуска приложений в песочнице, — это контейнеры и Trusted Execution Environments (TEE).
Контейнеры
Контейнер Linux — представлен в виде минимальной файловой системы, содержащей только необходимые программные компоненты для запуска определенного приложения или группы приложений. Контейнер работает полностью изолированно от основной системы, и работает только на ядре Linux.
Технология контейнеризации приложения в Linux базируется на функция ядра Linux, таких как:
- Пространство имён (namespaces): позволяет изолировать и виртуализировать глобальные системные ресурсы множества процессов. Примеры ресурсов, которые можно виртуализировать: ID процессов, имена хостов, ID пользователей, доступ к сетям, межпроцессное взаимодействие и файловые системы;
- Контрольная группа (cgroups): позволяет разделять системные ресурсы (ЦП, память, ввод-вывод) по процессам или группам процессов;
- Seccomp (secure computing mode): позволяет ограничить системные вызовы, которые может выполнять процесс. Если злоумышленник получит возможность выполнить произвольный код, seccomp не даст ему использовать системные вызовы, которые не были заранее объявлены.
Для работы с контейнерами в Linux существуют менеджеры облегчая создание, эксплуатацию, изменение контейнеров, такие как: LXC, Systemd-nspawn, Podman и самый популярный Docker.
Использование контейнерезации приложений сам по себе не является гарантией защиты системы, требуется правильно ограничить разрешения каждого процесса внутри контейнера и контролировать обмен данными между ними, уменьшая вектор атак и повышая безопасность системы.
В случае использования Docker при создания файла сборки образа — Dockerfile, необходимо воспользоваться лучшими практиками — Best practices for writing Dockerfiles. Интересный проект Dockle позволяет выполнить статистический анализ файла Dockerfile и получить отчет о проблемных местах. Запускать Dockle можно путем использование утилиты, или из контейнера.
![](https://habrastorage.org/webt/77/r8/uu/77r8uuxl0mpjf3bdasspuw6lsdq.png)
Полученный отчет безопасности от Dockle
Помимо Dockle существуют и другие инструменты для статистического анализа, более подробно можно ознакомится в публикации — 10+ top open-source tools for Docker security.
Комбинируя использование контейнеров вместе с модулем безопасности (например, AppArmor или SELinux), можно существенно повысить защиту системы.
В системе основанной на контейнерах, если ядро ОС будет скомпрометировано, то и вся операционная система окажется под угрозой. В этом случае доверенная среда выполнения — это еще один уровень безопасности, который может это предотвратить.
Доверенная среда выполнения
Доверенная среда выполнения (Trusted Execution Environment, TEE) — это среда, изолированная и защищенная с точки зрения конфиденциальности (никто не имеет доступа к данным) и целостности (никто не может изменить код) в которой исполняется код и хранятся данные.
В системе с доверенная среда выполнения (TEE) приложения делятся на:
- Ненадежные приложения (untrusted applications, UA), работающие в Rich Execution Environment (REE);
- Доверенные приложения (trusted applications, TA), работающие в Доверенной среде выполнения.
Только доверенные приложения, работающие в TEE (Secure World), имеют полный доступ к основным аппаратным ресурсам, периферийным устройствам и памяти. Аппаратная изоляция защищает доверенные приложения (ТА) от ненадежных приложений, работающих в основной операционной системе (Non-Secure World).
![](https://habrastorage.org/webt/kh/xi/ic/khxiicskxuxee9nty-tztdlpyva.png)
Схема работы системы вместе с доверенной средой выполнения
Для использование доверенной среды выполнения (TEE) необходима поддержка на уровне аппаратного обеспечения, для возможности разделения и изолирования оборудования (шины, периферийные устройства, области памяти, прерывания и т. д.), чтобы предотвратить доступ ненадежных приложений к защищенным ресурсам. Эта функция уже присутствует в большинстве современных процессоров (например, TrustZone ARM, MultiZone RISC-V, Intel SGX).
Доверенная среда выполнения используют многие устройства, такие как: смартфоны, телевизионные приставки, игровые консоли и Smart TV. Существуют коммерческие реализаций TEE: Kinibi, QSEE и iTrustee. И реализации с открытым исходным кодом: Trusty и OP-TEE. TEE может быть хорошим решением для приложений-песочниц, хранения и управления ключами шифрования, хранения учетных данных и конфиденциальных данных и управления ими, а также защиты информации, защищенной авторским правом.
Несмотря на все меры, которые были рассмотрены выше, операционная система с миллионами строк кода обязательно будет содержать ошибки и уязвимости! А наличие системы обновлений очень важно для встраиваемых систем и подключенных устройств, где безопасность является ключевой особенностью продукта.
Система обновлений
Система обновлений должна быть спроектирована на ранних этапах разработки продукта, по возможности с поддержкой OTA (обновление по беспроводным каналам связи, Over-the-Air). Использование системы обновления создает для некоторые проблемы для разработки продукта, включая безопасность протокола связи, атомарность процесса обновления, защиту от сбоев питания, использование полосы пропускания и хранилища, возможности отката и т. д.
Реализовать систему обновление можно в соответствие с основными стратегиями, такими как:
- На основе приложений: легко реализовать, но как насчет остальной части операционной системы?
- На основе пакетов: образы обновлений небольшие, но обновления не атомарны, и зависимости пакетов могут создать дополнительные проблемы;
- На основе образа: использование механизма A/B — очень хорошее решение, но загрузка целиком всего образа может быть проблемой в случаях низкой пропускной способности Интернет-канала, а так же потребуется в два раза больше пространства в хранилище для сохранение нового образа;
- На основе контейнера: одна из лучших стратегий. Размер нового контейнера будет существенно меньше чем обновление целиком из образа. Обновление является атомарным, отказоустойчивым, использует меньшую полосу пропускания, и процесс обновления проходит быстрее с минимальным временем простоя и возможностью отката.
Необходимо помнить что использование OTA-обновлений приводит к увеличению вероятности атак, т.к. устройство будет взаимодействовать с внешним миром через различные сетевые соединение (Wi-Fi, Ethernet и т. д.), и поэтому потребуется дополнительные уровни безопасности.
Сетевая безопасность
Правило здесь очень простое — максимально уменьшите поверхность атаки:
- Закрыть все неиспользуемые порты TCP/UDP
- Отключите все неиспользуемые протоколы (например, IPv6, PPP и т. д.)
- Настройте правила брандмауэра для предотвращения входящих/исходящих соединений
- Защитите от DoS атаки
- Предотвращение сканирования портов и т. д.
Если необходимо взаимодействовать с внешним миром, то всегда используйте только безопасное соединение (VPN, reverse SSH tunneling, TLS, HTTPS и т. д.), для удаленных подключений лучше использовать аутентификацию с открытым ключом, и отключите вход в систему root пользователю.
Заключение
В публикации не ставилась цель детально углубляться в реализации указанных технологий защиты кода и данных, самое главное заключалась в предоставление понимания технологий и концепций для снижения рисков и реализации более безопасного устройства работающего на Linux.
В сфере безопасности существует концепция многоуровневой защиты, при которой всегда необходимо реализовывать более одного уровня или типа защиты. Представьте себе, что вы король замка. Как бы вы защитили свой замок? Вы можете построить замок на вершине холма, построить высокие стены, окружить замок рвом с водой, расставить лучников на вершине стены, разместить воинов внутри замка и т. д. — это все уровни защиты. Если атакующий проходит один уровень защиты, ему/ей придется столкнуться со следующим, и так далее.
Эту же концепцию можно применить и при разработке встраиваемого устройства на Linux.
![](https://habrastorage.org/webt/2u/px/nl/2upxnll9x2mkm1ja4pzkbjhipvu.png)
Многоуровневая схема защиты по типу «матрешки»
В конце концов, не существует 100% защищенной системы. В отличие от вас, злоумышленнику необходима только одна уязвимость, чтобы взломать устройство. Любой взлом, это вопрос времени. Поэтому защита устройств это постоянный непрерывный процесс, который требует постоянного совершенствования технологий и инструментов защиты. Но необходимо не забывать, что система должна быть «достаточно безопасной». Использование методом защиты должно быть рациональным, иначе мы столкнемся с трудностями эксплуатации систем и только понизим уровень безопасности устройства.