Ошибки на уровне кода — бомба замедленного действия с точки зрения безопасности. Даже небольшие факапы, дыры и «костыли» могут обернуться большой проблемой и привести к реализации различных киберугроз.
В этой статье расскажем о распространённых угрозах для приложений, принципах безопасной разработки и роли облаков в обеспечении безопасности.
Материал подготовлен на основе вебинара «Безопасность на уровне кода: как эту задачу помогает решать облако».
Наиболее распространённые угрозы для приложений
Есть две общепринятые классификации актуальных угроз современным приложениям — 2023 CWE Top-25 и OWASP Top-10 Cloud Native. В них приведены ошибки, используя которые, злоумышленники могут потенциально получить полный контроль над уязвимыми системами, украсть конфиденциальные данные или вызвать состояние «отказа в обслуживании».
Рейтинг 2023 CWE Top-25 больше охватывает ошибки, связанные с кодом:
- CWE-787 — запись вне буфера (Out-of-bounds Write);
- CWE-79 — межсайтовый скриптинг (XSS);
- CWE-89 — SQL-инъекции;
- CWE-416 — использование указателя после освобождения памяти;
- CWE-78 — внедрение команд ОС;
- CWE-20 — некорректная валидация данных;
- CWE-125 — чтение вне буфера;
- CWE-22 — выход за пределы каталога;
- CWE-352 — подделка межсайтовых запросов;
- CWE-434 — неограниченная загрузка файла с опасным типом.
Самое страшное здесь — внедрение команд в ОС (CWE-78), для веб-приложений:
- подделка межсайтовых запросов (CSRF);
- выход за пределы каталога (Path Traversal);
- SQL-инъекции;
- межсайтовый скриптинг (XSS).
OWASP Top-10 Cloud Native больше ориентирован на ошибки, связанные с конфигурациями построенных систем. Среди наиболее частых ошибок здесь:
- CNAS-1 — небезопасная конфигурация облачных ресурсов, контейнера или оркестратора;
- CNAS-2 — уязвимости типа «инъекция» (SQL, XXE, NoSQL и другие);
- CNAS-3 — некорректная аутентификация и авторизация;
- CNAS-4 — уязвимости в пайплайне CI/CD и цепочках поставок;
- CNAS-5 — небезопасное хранение секретов;
- CNAS-6 — небезопасные сетевые политики или политики с чрезмерными правами;
- CNAS-7 — использование компонентов с известными уязвимостями;
- CNAS-8 — некорректное управление ресурсами в облаке;
- CNAS-9 — некорректно заданные квоты на облачные ресурсы;
- CNAS-10 — неэффективное логирование и мониторинг.
Каждая из этих уязвимостей может быть использована злоумышленниками для атак на приложения и привести к серьёзным последствиям, таким как несанкционированный доступ к данным, выполнение произвольного кода, нарушение в работе ПО или утечка конфиденциальной информации.
При этом в каждом конкретном случае может быть реализована своя уязвимость — это не обязательно будет условная CWE-787, занимающая первое место в топе по популярности.
Также надо учитывать, что корень большинства уязвимостей именно в ошибках на уровне кода. По статистике, разработчик делает одну ошибку на каждые 42 строчки кода, и многие языки программирования не могут их выявить в исходной структуре. Поэтому при разработке важно следовать определённым принципам и правилам.
Основные принципы безопасной разработки
Чем раньше выявлена уязвимость, тем меньше ресурсов и времени нужно на её устранение и ликвидацию последствий. Лучшая ошибка — та, которую не допустили.
Поэтому проектировать приложения нужно с учётом потенциальных рисков и модели угроз. Чтобы не создавать десятки контуров в попытке защититься сразу от всего, лучше предварительно проводить статический анализ. Он покажет, какие проблемы безопасности обычно возникают в ПО того или иного типа.
Также стоит придерживаться принципов безопасной разработки. Компания OWASP выделяет 12 рекомендаций:
-
Отсутствие гарантий безопасности (No security guarantee). Самый безопасный компьютер — тот, который выключен и закопан в землю. При проработке мер безопасности надо исходить из того, что нельзя быть полностью уверенным в чём-то: риски можно минимизировать, но нельзя исключить. В результате важно на уровне кода сделать защиту достаточно сложной, а потенциальный ущерб — минимальным, чтобы злоумышленнику было нерационально даже начинать атаку.
-
Глубинная (эшелонированная) защита (Defense in depth). Надёжная защита — та, которая выстроена с использованием нескольких инструментов или механик и учитывает все потенциальные риски. Логика в том, что никогда нельзя гарантировать отсутствие сбоев или слепых зон в работе ПО, поэтому надо иметь дублирующий контур. Например, в случае API-сервиса лучше проводить санитайзинг-данные как на входе, так и на выходе. Также желательно помещать критические компоненты в «бастионы» с максимальной защитой и общаться с ними через коннекторы.
-
Отказобезопасность (Fail safe). Приложения нужно разрабатывать так, чтобы в случае инцидента влияние на пользователей было минимальным: ПО должно продолжать работать полностью или частично. Для этого желательно строить приложения на основе микросервисов, создавать реплики критически важных компонентов и стараться обеспечить максимальную отказоустойчивость модулей с пользовательскими данными. Например, для этого хорошо подходит работа в Kubernetes: можно закатать приложение в виде деплоймента и в случае сбоев на уровне деплойментов они автоматически перезапустятся, поддерживая стабильность работы приложения.
-
Минимизация полномочий (Least privilege). Приложению нужно предоставлять только необходимые полномочия и доступ к ресурсам. На уровне кода это может быть реализовано с помощью принципа наименьших привилегий: каждый компонент приложения должен иметь только те полномочия, которые необходимы для его работы. Если же нужны расширенные права (например, на время теста), то нужно контролировать, чтобы они не остались активными уже в проде.
-
Разделение ответственности (Separation of duties). Стоит разделять функциональность и ответственность между разными компонентами приложения на уровне кода. Как и в случае с минимизацией полномочий, это может быть реализовано с помощью модульной или микросервисной архитектуры, при которой каждый микросервис имеет разные права доступа — чётко в рамках своих задач.
-
Упрощение механизмов безопасности (Economy of mechanism). Переусложнение защиты может привести к тому, что обвес мер безопасности может быть настолько сложным, что сам по себе станет представлять большую поверхность атаки, а управлять им будет неоправданно трудно. Более того, при комбинировании многих инструментов нужна глубокая настройка, чтобы решения ошибочно не реагировали друг на друга. Это не значит, что безопасностью можно пренебречь: нужен баланс.
-
Полное посредничество (Complete mediation). Важно, чтобы все процессы и цепочки поставок были отфильтрованы и авторизованы: игнорирование этих мер даже на небольших этапах создаст бреши в защите. При этом разграничения важно делать не на фронтенде, а на бэкенде, на уровне кода. Например, каждую запрашиваемую страницу надо проверять каждый раз, а не только при первой аутентификации.
-
Публичная информация об архитектуре (Open design). Информация об архитектуре должна быть непубличной, но часть данных можно оставлять на виду, в пределах минимальной достаточности. Например, вполне может существовать публичная информация об API-контрактах, но реализация должна быть скрыта внутри и по этим контрактам не должно быть понятно, что, например, при генерации паролей используется некие соль и хеш.
-
Минимизация общих процессов (Least common mechanism). Важно сократить переиспользование компонентов, если в разных системах с ними взаимодействуют пользователи с разными правами доступа. Также минимизация общих процессов сокращает риски в случае взлома модуля: чем меньше его влияние, тем меньше систем пострадает.
-
Психологическая приемлемость (Psychological acceptability). При выстраивании систем безопасности важно учитывать не только их надёжность, но и удобство для конечного пользователя. Десятки капч и слишком сложные пароли не всегда хорошо. Ведь если ставить слишком жёсткие требования, люди прибегают к «теневому ИТ» — начинают пользоваться сервисами в обход корпоративных систем со всеми рисками безопасности.
-
Принцип самого слабого места (Weakest link). Безопасность системы ограничена её самым слабым компонентом. Поэтому при проектировании и эксплуатации важно отслеживать «бутылочные горлышки» в безопасности и стремиться расширить их, сделать надёжными и обеспечить мониторинг. На уровне кода это можно обеспечить тестированием.
-
Использование существующих компонентов (Leveraging existing components). Рациональнее и проще не создавать дополнительные модули защиты под каждый конкретный случай, а использовать компоненты и библиотеки безопасности, которые уже работают, отлажены и понятны. Кроме упрощения технической реализации, это и экономически выгоднее: даже если придётся несколько адаптировать компоненты, на это уйдёт меньше ресурсов и времени, чем на разработку с нуля.
Инструменты безопасной разработки
Есть несколько инструментов, которые рекомендуют использовать для написания безопасного кода. В рамках OWASP DevSecOps Guideline выделяют восемь таких решений:
- Credentials leakage scanning (SDLC).
- Static application security testing (SAST).
- Software component / Composition analysis (SCA).
- Interactive application security testing (IAST).
- Dynamic application security testing (DAST).
- IaC scanning.
- Infrastructure scanning.
- Compliance check.
В контексте обеспечения безопасности на уровне кода приоритетными являются первые три из списка.
-
Credentials leakage scanning — сканирование утечек учётных данных. Используется для обнаружения утечек паролей, ключей доступа и других секретов, что может привести к компрометации аккаунтов пользователей, нарушению конфиденциальности данных или несанкционированному использованию привилегий. Утечки ищут в различных источниках, включая код приложения, конфигурационные файлы, базы данных и другие хранилища.
-
Static application security testing (SAST) — статический анализ безопасности приложений. Применяется для поиска в исходном коде приложения потенциальных уязвимостей без его фактического выполнения. Анализируя структуру и логику кода, ищут инъекции SQL, уязвимости XSS, неправильное использование криптографии и другое, а также формируют отчёты с рекомендациями по их устранению. SAST помогает выявить уязвимости на ранних стадиях разработки, что позволяет разработчикам исправить их до выпуска приложения.
-
Software component / Composition analysis (SCA) — анализ компонентов, то есть состава ПО для поиска известных уязвимостей. SCA-инструменты сканируют используемые библиотеки, фреймворки и другие компоненты на наличие известных уязвимостей или проблем безопасности. Это позволяет разработчикам обновлять или заменять уязвимые компоненты и обеспечивает безопасность приложения.
Логирование vs Logging vs Tracing vs Monitoring
Кроме инструментов для исключения ошибок и уязвимостей на этапе разработки и ранних релизов, для обеспечения безопасности уже на этапе эксплуатации важно проводить логирование, мониторинг и отслеживание.
-
Logging (логирование). Используется для записи информации о работе приложения, включая ошибки, исключения, события и другую отладочную информацию. Логирование позволяет разработчикам отслеживать и анализировать проблемы безопасности, проверять соответствие политикам безопасности, анализировать уязвимости, а также расследовать инциденты.
-
Tracing (отслеживание). Используется для отслеживания выполнения операций внутри приложения. Позволяет разработчикам следить за потоком выполнения кода, анализировать его и искать уязвимости и проблемы безопасности. Отслеживание должно быть предусмотрено при написании кода для критических функций и операций, а также для операций, связанных с безопасностью.
-
Monitoring (мониторинг). Используется для непрерывного контроля работы приложения в реальном времени. Позволяет отслеживать производительность, доступность и безопасность приложения, а также обнаруживать и реагировать на угрозы и проблемы безопасности. Мониторинг может включать проверку журналов, отслеживание метрик производительности, анализ сетевого трафика и другие методы.
Облачные инструменты для создания безопасных приложений и информационной безопасности
Один из вариантов создания и развёртывания безопасного приложения с возможностью мониторинга защиты на всех этапах эксплуатации — миграция в облако. Работа в облачной среде даёт несколько преимуществ.
-
Повышение защиты. Как правило, облачные провайдеры стараются максимально обезопасить собственную инфраструктуру и ресурсы, доступные клиентам. Для этого сервисы создают на основе защищённых ЦОДов, инфраструктуру сертифицируют, а на программном уровне подключают передовые инструменты безопасности и разделения прав доступа. Выстроить такую систему на своей инфраструктуре сложно, долго и дорого. Например, ЦОДы VK Cloud сертифицированы по Tier-3, а облачная платформа аттестована на соответствие требованиям 152-ФЗ (УЗ-1). По данным Gartner, в облаке риск инцидентов снижается на 60%.
-
Делегирование обязанностей. За инфраструктуру, администрирование сервисов и их своевременное обновление, а также защиту от атак на внешний контур в облаке отвечает провайдер. Это позволяет нативно исключать распространённые угрозы, а также не допускать уязвимости, связанные с устаревшими версиями программного обеспечения или неприменёнными патчами.
-
Доступность нужного стека. Облачные провайдеры предоставляют большой стек инструментов, которые можно подключить в несколько кликов. Например, настроить логирование, мониторинг, резервное копирование и восстановление, развернуть решения AntiDDoS и не только. При этом задачи глубокой настройки инструментов, их лицензирования и доступности остаются на стороне облачного провайдера — пользователь может сосредоточиться исключительно на работе с продуктом.
-
Масштабируемость. Облачные платформы позволяют масштабировать приложения и ресурсы под нагрузку и обеспечивают отказоустойчивость с помощью её распределения по нескольким серверам и ЦОДам. Например, это важно, когда нужно провести сложные сканирования или обработать большое количество отчётов от системы безопасности.
Облачные технологии предоставляют широкий спектр инструментов и механизмов для обеспечения безопасности приложений — от физической безопасности и защиты сети до шифрования данных и мониторинга угроз. Они также позволяют разработчикам и администраторам приложений сосредоточиться на безопасности кода и использовать соответствующие практики разработки.
Ключевое по теме
В условиях повышения сложности и интенсивности киберпреступлений защита приложений и других ИТ-продуктов — первоочередная задача любого разработчика. При этом лучшие практики показывают, что думать о безопасности нужно не перед запуском в прод, а ещё на «нулевых» этапах — в момент проектирования решения и начала его разработки. С учётом угроз, актуальных для современных приложений, предусматривать меры безопасности лучше на этапе написания кода. В таком случае легче закрыть все бреши в защите, сократить взаимные риски, снизить зависимость модулей приложения друг от друга. При этом для обеспечения безопасности на этапе развёртывания и эксплуатации ПО больше подходят облака: можно получить доступ к широкому стеку инструментов, повысить защиту и делегировать часть задач провайдеру.