Устранение уязвимостей в коде

Сегодня решил рассказать об одном аспекте в разработке ПО, про который очень часто несправедливо забывают. Это способы изоляции приложения и системы, в которой это приложение исполняется.

Какой бы классный и неуязвимый код мы ни писали, мы используем внешние зависимости - сторонние библиотеки, которые могут содержать различные уязвимости. Поэтому будет справедливо утверждать, что любой код имеет уязвимости. Раз так, то давайте разберемся с тем, как минимизировать свои риски.

Если код содержит уязвимости, он должен исполняться в изолированной среде, которая запретит доступ к тем частям системы, которые могут быть скомпрометированы. Классически выделяют три подхода изоляции процессов ОС.

  • Wrapper / Обертка. Изолируемый процесс запускается с помощью программы, которую называют “обертка” (wrapper). Перед запуском изолируемого процесса обертка создает необходимое окружение для его исполнения, что чаще всего заключается в ограничении прав и лимитировании ресурсов. После этого изолируемый процесс запускается внутри предоставленного окружения, т.е. “оборачивается” в него. Этот подход универсальный и простой, используется для изоляции сторонних приложений. По этому принципу сделаны cgroup (cgexec), ранее рассмотренный Bubblewrap, любые другие средства контейнеризации. Основной недостаток - окружение создается со всеми правами, которые могут понадобится для работы изолируемого процесса (даже если они нужные ему только однажды, например, при старте или инициализации).

  • Self-sandboxing / Самоизоляция. Приложение самостоятельно накладывает ограничения на доступ к некоторым аспектам системы. Кто лучше всех знает, что именно нужно приложению для его работы? Правильно, разработчик этого приложения. Если, например, мы знаем, что доступ к файловой системе нам нужен только на этапе запуска, когда мы считываем конфигурационный файл, то сразу после этого мы можем наложить самозапрет на доступ к файлам. Ясно, что такой подход уменьшает уязвимость всего остального кода приложения. Основной недостаток - динамическая самоизоляция может неожиданно нарушить работу других частей приложения, поэтому ее лучше применять для каких-то базовых ограничений (например, доступ к файловой системе) или в простых приложениях.

  • Broker / Брокер. Изолируемый процесс получает доступ к системе через посредника - брокера. Таким образом, брокер контролирует все обращения к любым системным ресурсам. Этот подход отлично себя зарекомендовал, используется в Chromium, Firefox, мобильных платформах (Android, iOS). Большие усилия в развитии этого подхода для графических приложений Linux предприняты в рамках проекта D-Bus. Основной недостаток - сложность реализации и снижение производительности приложения из-за накладных расходов брокера на виртуализацию доступа к системным ресурсам.

Все представленные подходы могут комбинироваться друг с другом.

Как мне кажется, “Самоизоляция” - недооцененный подход. Был ли у вас опыт его использования? ;-)



Понравилась статья?

Посмею напомнить, что у меня есть Telegram-канал Архитектоника в ИТ, где я публикую материал на похожие темы примерно раз в неделю. Подписчики меня мотивируют, но ещё больше мотивируют живые дискуссии, ведь именно в них рождается истина. Поэтому подписывайтесь на канал и будем оставаться на связи! ;-)

Статьи из той же категории: