ADG Оставить заявку
Блог Информационная безопасность 5 мин чтения

DevSecOps H1 2018: итоги полугодия SAST/DAST - что нашли, что поправили

Полугодовые результаты DevSecOps-внедрений: 60%+ критических уязвимостей пойманы на стадии разработки. Публикуем метрики, кейсы и честные наблюдения.

Контекст момента

Обзор DevSecOps-практик: результаты интеграции SAST/DAST в CI/CD за H1 2018

В конце апреля мы писали про первый опыт встраивания SAST в GitLab CI - тогда это был свежий эксперимент на одном финтехе, и мы честно не знали что получится. Прошло два месяца, проектов стало больше, цифры накопились. Самое время посмотреть на всё это без розовых очков.

Что считали и как

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

Тем не менее по итогам H1 у нас есть общая картина по классам находок и по тому, где они обнаруживались. Ключевой результат: больше 60% HIGH-уязвимостей, которые мы в итоге классифицировали как критические или высокого риска, поймал автоматический анализ до попадания кода в production. Это не значит что без DevSecOps они бы все попали в прод - часть ловилась бы на code review, часть на ручном аудите. Но часть - нет, и именно это интересно.

Топ находок: что повторялось у всех

Паттерны оказались неожиданно однотипными у разных клиентов:

Хардкод секретов. Токены, ключи API, тестовые пароли - в конфигах, в тестовых фикстурах, в скриптах деплоя. Это классика и про неё все знают, но знать и не иметь - разные вещи. Bandit и аналогичные инструменты ловят это правилами B105/B106, и они срабатывали на каждом проекте в первые дни. Не потому что разработчики плохие - потому что без автоматической проверки это просто не всплывает.

Небезопасная десериализация. pickle.loads() без проверки источника, yaml.load() вместо yaml.safe_load(). Несколько раз встречалось в сервисах, которые принимали данные из внутренних очередей - «внутреннее, значит безопасное» логика, которая разваливается в тот момент, когда атакующий добирается до очереди.

Отключенная верификация TLS. verify=False в requests, InsecureRequestWarning засупрессированы. Примерно в половине проектов обнаружились такие вызовы к внутренним сервисам. Объяснение всегда одно: «у нас самоподписанный сертификат на внутреннем сервисе, некогда было разбираться». Это не уязвимость с немедленным вектором эксплуатации, но это техдолг который копится.

SQL-инъекции через конкатенацию строк. На Go- и PHP-проектах это всплывало стабильно - где-то в легаси-коде, где-то в «быстро сделанном» разделе. Иногда за годы разработки.

Где помогло больше всего: история с DAST

SAST мы внедрили раньше, DAST - в конце апреля - мае. DAST (у нас OWASP ZAP в активном режиме против тестового окружения) оказался дополнением, а не альтернативой.

Один кейс показательный. На ритейл-проекте SAST не нашёл ничего критического в модуле личного кабинета - код был написан аккуратно, без явных паттернов-нарушителей. DAST против тестового стенда за несколько часов нашёл IDOR в API: можно было подставить чужой order_id в запрос и получить чужой заказ. Никакой статический анализ это не поймает - это логическая уязвимость в бизнес-логике, не паттерн в коде. Разработчики воспроизвели руками, убедились, поправили за день.

При этом DAST дал существенно больше false positives - особенно на аутентификацию и авторизацию в сложных сценариях. ZAP не всегда понимает контекст сессии, лезет не туда, генерирует алерты которые при проверке оказываются ничем. Мы потратили время на настройку контекстов и exclusion-правил, прежде чем шум опустился до приемлемого уровня.

Цифры, которые стоит воспринимать осторожно

Мы избегаем публиковать точные числа по конкретным проектам - это данные клиентов. Но несколько наблюдений, которые повторились везде:

  • Первые 2-3 недели после подключения SAST - всегда много шума. Старый код, накопленные # nosec-кандидаты, false positives на специфику проекта. Нужно это пережить, настроить пороги, согласовать с командой правила suppression.

  • Через 4-6 недель поток HIGH-находок на новом коде резко снижается. Разработчики начинают проверять сами перед коммитом, привыкают к паттернам которые Bandit/gosec считают проблемными. Это и есть тот образовательный эффект, про который говорят в DevSecOps - только он случается не сразу.

  • DAST нужен отдельный стенд и внятный граф сценариев тестирования. Запустить ZAP против тестового окружения без настройки - это примерно ничего полезного плюс куча шума.

Что не работает так, как написано в презентациях

Честно про боль: интеграция DevSecOps в живые команды - это не технический проект. Это организационный. Первые недели разработчики воспринимают SAST как «ещё одну вещь которая блокирует MR». Один из клиентов пришёл к нам с запросом «отключить эту штуку, она мешает». Мы не отключили - вместо этого провели разбор конкретных находок с командой, объяснили контекст уязвимостей. После двух таких сессий отношение сменилось.

Инженер по безопасности должен быть реально вовлечён в pipeline - не как человек который смотрит отчёты раз в неделю, а как участник ревью конкретных алертов, особенно в первые месяцы. Иначе SAST превращается в генератор ignored warnings.

Что дальше

Продолжаем наращивать покрытие - подключаем проверки на зависимости (OWASP Dependency Check, safety для Python) и на конфигурацию инфраструктуры. Идея одна: чем левее в пайплайне находка, тем дешевле исправление. Это банально, но работает именно так.

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

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.