Как сократить число уязвимостей при разработке приложений

Любое программное обеспечение неизбежно содержит уязвимости, причем на любом этапе своего жизненного цикла. Избавиться от изъянов невозможно, однако всегда полезно применять испытанные методы и приемы, позволяющие сократить число потенциальных брешей. Практический опыт создания безопасных программных продуктов, представленный с точки зрения активно развивающегося системного интегратора, пригодится и корпоративному, и индивидуальному разработчику.


Введение

Продукт разработки программного обеспечения (далее — ПО) для внутренних нужд или для внешнего заказчика гарантированно уязвим в определенной мере. Причины этого очевидны. Существуют проблемы языка разработки (библиотек, среды выполнения runtime): например, в приложениях, созданных на языке Java, регулярно находят уязвимости. Уязвимы сами платформы функционирования и разработки. Не идеальны внешние подключаемые модули и дизайн программного обеспечения. Зачастую плохо организован сам процесс разработки.

Отдельного упоминания заслуживает процесс получения обновлений приложений, его недостаточная продуманность и организованность.

Наконец, причиной появления уязвимостей могут служить непосредственно ошибки и недоработки программистов: плохая преемственность разработчиков и как следствие наслоение кода, появление лишних сущностей, отсутствие проверки ввода и вывода, документирования и комментирования кода, отсутствие унификации и так далее.

Сказываются и давление со стороны бизнеса (диктуются сроки и программные доработки — feature requests), и отсутствие понимающей позиции у коллег-безопасников, сетевиков, инфраструктурщиков (один сервер под множество баз данных разного уровня доверия) — эти факторы приводят к увеличению рисков информационной безопасности ПО. Например, нередка ситуация: программная доработка требует организации нового сетевого общения между серверными компонентами, но согласование нового сервиса требует такого количества времени, которое в соблюдение даты закрытия запроса на доработку (feature request) не вписывается; разработчик ускоренно «ковыряет дырку» в знакомом месте, в обход политики ИБ, возможно, даже с временным согласованием безопасника при условии, что потом все будет сделано как следует, но почти наверняка это «потом» не наступает, и в архитектуре остается уязвимость.

Как показывает практика, многих проблем можно избежать, если заранее учитывать эти и другие подобные факторы.

Стратегия уменьшения рисков

Абсолютно безопасное приложение создать невозможно, как и панацею от всех болезней, но качественная организация разработки вполне способна минимизировать риски. Можно применить так называемую «модель швейцарского сыра»: сыр многослоен, и в каждом слое есть дырки; слои сыра — это слои защиты (на уровне организации процесса и регламентов, на уровне архитектуры, на уровне кода и так далее), а дырки — это ошибки реализации. Если смотреть на сыр снаружи, то сквозных отверстий не видно (поскольку дырки в разных слоях не совпадают), а значит, система стабильна и безопасна. Соответственно, несмотря на наличие в каждом отдельном слое ошибок или недоработок, системе в целом удается избежать глобальной аварии.

Для внутренних приложений риски несанкционированного проникновения можно снизить за счет инфраструктурных решений. Для внешнего продукта и этот механизм является неконтролируемым, так что возможно лишь дать рекомендации к архитектуре установки и к организации ее информационной безопасности.

Для снижения рисков информационной безопасности в конечном продукте рекомендуется проработать и усилить следующие аспекты разработки:

В части организации процесса разработки:
  • использование проработанных фреймворков;
  • необходимое и достаточное комментирование кода, ведение документации, использование внутреннего Вики;
  • производить регулярную ревизию кода. Да этот процесс менее приоритетен, чем разработка программных доработок, но уделять на него часть продуктивного времени разработчиков необходимо.


В части организации процесса тестирования: организовать регулярность этого этапа, без игнорирования несмотря на желаемые сроки выхода продукта. Лучше выпустить продукт позже, чем не качественно протестированным. А так же использовать разные типы тестирования:
  • динамическое и статическое тестирование на уязвимости. Для этого существует целый класс решений - средства анализа кода;
  • регрессионное тестирование продукта;
  • фаззингтестирование (или fuzz тестирование, fuzzing) – «техника тестирования программного обеспечения, автоматическая или полуавтоматическая, заключающая в передаче приложению на вход массива неправильно сформированных или случайных данных» (ист. ru.wikipedia.org) – ресурсоемкая процедура с не таким высоким коэффициентом полезного действия, но, при возможности полноценной реализации, дающее свои результаты. "ГОСТ Р 56939-2016 Защита информации. Разработка безопасного программного обеспечения. Общие требования" рекомендует использование данной процедуры;
  • периодическое проведение процедуры тестирования на проникновение (Pentest).

 В вопросе дизайна и архитектуры программного обеспечения (далее – ПО):
  • использование аутентификации, в идеале на сертификатах, даже во внутреннем взаимодействии, даже для доверенного администратора или разработчика;
  • отказ от использования слабых протоколов передачи данных (ftp, http, smb);
  • не класть «все яйца в одну корзину»: существует много решений виртуализации или контейнеризации - менее ресурсоемкий вариант, который так же дает достаточный уровень изоляции сервисов друг от друга;
  • изоляция сетевой среды, в первую очередь отделять front-end компоненты от рисковых компонент и баз данных;
  • ограничение ввода и вывода данных: объема загрузки и выгрузки, количества и формата записей, и так далее;
  • отказ от использования полных привилегий (root) на любых этапах взаимодействий, включая административные;
  • использование безопасных криптографических алгоритмов.

 В вопросе выбора платформы и компилятора:
  • по возможности использование платформ со встроенными проверками безопасности: технологий ASLR (рандомизация схемы адресного пространства), CRED (C range error detector), и др.;
  • использование по возможности компиляторов со встроенными контролями, например, GCC (GNU Compiler Collection), использование MSVC (Microsoft Visual C++);
  • выполнение обновлений платформы, компилятора, языка. Хотя эта ресурсоемкая операция не дает прямых выгод для продукта, уровень информационной безопасности и разработки заметно поднимается.

 В вопросе анализа рисков:
  • периодическое моделирование угроз с трансляцией результатов в отдел разработки;
  • формирование у разработчиков продуманного подхода к продукту через регулярные обучения.

Вот что рекомендует эксперт компании «Авито» Евгений Харченко:

«Фактически, нужно использовать подход «нельзя верить никому»:

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

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

Обеспечивать безопасность внешнего трафика: например, если ожидаешь, что пользователь напишет тебе число, то что бы он ни прислал — приведи это к числу. Тогда будешь уверен, что дальше работаешь с числом, и в самом критическом случае избежишь shell-инъекции.

Не использовать сторонние компоненты, пока можешь их не использовать. Отправлять пользовательский ввод не в формате «взял-отдал», а в формате «взял-обработал-отдал». Следить за бюллетенями безопасности (Security Notes) к компонентам, устанавливать обновления, применять виртуал-патчинг.

Ограничивать физические доступы компонентов к внутренней инфраструктуре: например, если используешь сервис аутентификации, то не давать ему доступа к базе данных биллинга, и тогда в случае получения злоумышленниками контроля над ним диапазон потенциального риска будет ограничен.

Доводить это до паранойи не надо, но выполнять необходимые разграничения рекомендуется: использовать контейнеризацию или виртуализацию, ограничивать сетевые взаимодействия, выделять базы в защищенный контур, разделять их. Не допускать хождения всех сервисов с одними реквизитами в соседние таблички одной базы, как минимум разделять базы, возможно, использовать Docker или другие средства изоляции или виртуализации. Аккуратно организовывать сетевую видимость, не допускать лишних сервисов и так далее.

Полезно иметь базовую модель угроз, желательно — с типовыми примерами, и сделать ее доступной непосредственно команде разработки и даже обязательной к регулярному ознакомлению.

И, конечно, необходимо работать над внутренней культурой общения между подразделениями информационной безопасности и разработки. Каждый их представитель должен понимать, что первостепенная задача — это эффективное взаимодействие, а не попытка перекладывания ответственности с одних плеч на другие, и их общая цель — это качественный и своевременный продукт».

Стандарты и рекомендации

В вопросах организации и процессов безопасной разработки существует много стандартов и рекомендаций. 1 июня 2017 года введен в действие для добровольного применения ГОСТ Р 56939-2016 «Защита информации. Разработка безопасного программного обеспечения. Общие требования». Стандарт описывает комплекс мер, реализуемый в процессах функционирования и сопровождения ПО, формирования и поддержания среды обеспечения оперативного устранения выявленных пользователями ошибок ПО, направленный на снижение рисков появления уязвимостей. ГОСТ содержит перечень действий, которые рекомендуется осуществить на различных этапах жизненного цикла ПО, и является российским аналогом концепции SDL (Security Development Lifecycle).

В вопросе конкретных рекомендаций по разработке существует достаточно литературы с конкретными примерами — скажем, «Защищенный код» Майкла Ховарда и Дэвида Лебланка (Writing Secure Code), — а также отдельных узконаправленных статей, например, на сайте Habr (https://habr.com/ru/post/56291/, https://habr.com/ru/post/70330/). Кроме того, разработчикам полезно регулярно знакомиться с данными исследовательских организаций, в частности:

Однако никакие решения и процедуры не могут дать гарантии безопасности приложений, поэтому необходимо иметь проработанный план реагирования на инциденты ИБ, а также рассматривать целесообразность использования наложенных средств защиты приложений, в том числе:

  • защиты web-приложений WAF (Web Application Firewall),
  • защиты DNS,
  • защиты БД DBF (Database Firewall),
  • разграничения и фильтрации сетевых взаимодействий уровня NGFW, UTM, IPS-решений,
  • антивирусной защиты.

Кроме названных средств, в части статического и динамического тестирования выходного продукта существует упоминавшийся выше отдельный класс решений, направленных на поиск уязвимостей: анализаторы кода.

Средства анализа кода

Решения по анализу кода осуществляют поиск известных уязвимостей в разработанном коде ПО. Проверка выполняется как для исходного кода — статический анализ, или SAST (Static Application Security Testing), — так и для исполняемого — динамический анализ, или DAST (Dynamic Application Security Testing). Динамический анализ фактически является первым этапом тестирования на проникновение (penetration test) для приложения.

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

Подробный обзор продуктов класса анализаторов кода можно посмотреть в статье Екатерины Бойцовой.

Выводы

Одну из основных целей организации информационной безопасности можно сформулировать упрощенно: сделать так, чтобы злоумышленнику было максимально сложно взломать систему и получить доступ к информации. Действия, описанные в этой статье, направлены на создание эшелонов защиты продукта на разных уровнях производства и функционирования, и в первую очередь — повышения уровня осведомленности команды разработки в вопросах ИБ как наиболее эффективного средства защиты информации.

Анна Михайлова, системный инженер

 Автор: Анна Михайлова
 Системный архитектор
 Angara Technologies Group

Статья опубликована на www.anti-malware.ru




Другие публикации

Как не стать жертвой мошенников: рекомендации по настройке аккаунта в Telegram

Каждое юрлицо – это оператор персональных данных, который собирает большое количество личной информации: ФИО, номера телефонов, адреса, банковские данные.

актуально

26.07.2024

Повышение информационной безопасности АСУ ТП: практический кейс

Михаил Сухов, руководитель отдела анализа защищенности Angara Security, подготовил для Anti-malware статью о пентесте на одном из предприятий промышленного сектора.

06.06.2024

Angara Security: в России выявлены мошеннические площадки для сбора персональных данных в преддверии ЕГЭ и ОГЭ

Аналитики Angara Security выявили, что в апреле 2024 года были зарегистрированы домены, которые используют тематику подготовки к единому государственному экзамену.

31.05.2024

Лада Антипова, Angara Security: Неквалифицированное реагирование на инцидент только усугубит последствия для компании

При возникновении инцидента сотрудники компании без отдела ИБ рискуют совершить ошибки, которые затруднят расследование киберпреступления и могут привести к потере ценных данных. Лада Антипова, руководитель отдела реагирования и цифровой криминалистики Angara SOC, рассказала порталу Cyber Media.

актуально

29.05.2024

Перспективы российских облачных сервисов в условиях санкций

Денис Бандалетов, руководитель отдела сетевых технологий Angara Security, принял участие в подготовке материала об облачных сервисах и выборе решений с учетом задач инфраструктуры заказчиков для Коммерсантъ.

актуально

23.05.2024

Остались вопросы?

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

Подпишитесь на уведомления о новых материалах