Ненастроенный SAST - генератор шума. На практике дефолтные правила выдают 60–90% ложных срабатываний, а после тюнинга показатель падает до 10–20%. Для команды из 10 разработчиков с 40 PR в неделю разница между этими числами - порядка 24 инженерных часов, потраченных на разбор мусора вместо фикса реальных уязвимостей. Я прошёл этот путь на трёх проектах: Python-монорепо, кластер Go-микросервисов, TypeScript-фронтенд. Во всех случаях проблема была не в инструментах - их включили с дефолтными настройками и ждали чуда.
Почему статический анализ кода в пайплайне порождает шум
SAST-инструменты работают через паттерн-матчинг по AST (абстрактному синтаксическому дереву) или через полный семантический анализ с построением графа потока данных. Оба подхода отвечают на один вопрос: содержит ли код паттерн, ассоциированный с известным классом уязвимости? Ни один из них не скажет, эксплуатируема ли уязвимость в рантайме.Alert fatigue возникает на стыке трёх факторов:
- Дефолтные наборы правил покрывают максимальный спектр языков и фреймворков - за счёт точности
- Сканирование всей кодовой базы при каждом коммите превращает pipeline в бутылочное горлышко
- Отсутствие baseline приводит к отчёту о проблемах пятилетней давности при каждом запуске
Критерии отбора: почему Semgrep, CodeQL и SonarQube
Три инструмента - три архитектурных подхода к автоматическому анализу безопасности кода:- Semgrep - паттерн-матчинг с поддержкой taint-трекинга в Pro-версии; самый быстрый в CI/CD
- CodeQL - семантический анализ через реляционную базу кода; самый глубокий
- SonarQube - гибрид code quality и security с mature-средой; самый распространённый
tj-actions/changed-files, используемый во многих CI/CD-пайплайнах, был скомпрометирован в рамках атаки на цепочку поставок (T1195.002, Initial Access) - наглядная иллюстрация рисков зависимости от сторонних Actions. Bandit и ESLint security-плагины - одноязычные линтеры без cross-file анализа, для production-пайплайна недостаточны как самостоятельное решение.Архитектурные отличия трёх SAST инструментов
Semgrep - настройка правил за минуты
Semgrep парсит код в AST и применяет паттерн-матчинг с синтаксисом, который выглядит как целевой язык. Правило для поиска SQL-инъекции в Python визуально похоже на сам уязвимый код - порог входа в написание кастомных правил минимальный.Open-source CLI (лицензия LGPL 2.1) анализирует в рамках одного файла и одной функции. Semgrep Pro добавляет interprocedural taint analysis и cross-file отслеживание потока данных. Diff-aware сканирование работает по умолчанию, время анализа PR - секунды, даже на крупных кодовых базах.
Ограничения:
- Open-source версия не отслеживает data flow через границы функций и файлов - сложные taint-цепочки пропускаются
- Community-правила неоднородны по качеству и требуют ревью перед включением (я на одном проекте нашёл три правила, которые стабильно давали false positive на стандартном Django ORM - пришлось выкинуть)
- В 2024 году Semgrep изменил лицензирование части правил на Semgrep Rules License, ограничивающую коммерческое и SaaS-использование. Движок остаётся под LGPL 2.1. В январе 2025 появился community-форк OpenGrep без платного уровня
- Стоимость Pro: ориентировочно от $40/dev/month, актуальные цены - semgrep.dev/pricing
CodeQL - анализ уязвимостей на уровне семантики
CodeQL строит реляционную базу данных всей кодовой базы: каждая переменная, вызов функции и поток данных становятся queryable facts. Запрос на языке QL проследит, достигает ли user-controlled input точки SQL-выполнения через пять промежуточных функций и абстракцию базы данных. Принципиально другой подход: Semgrep ищет паттерны, CodeQL понимает семантику. Результат - самый низкий false positive rate среди инструментов в этом сравнении.Ключевая особенность, влияющая на выбор: CodeQL требует компиляции проекта для построения базы данных (для компилируемых языков: Java, Go, C/C++). CI-джоб должен иметь доступ ко всем зависимостям и build-инструментам. Для Python и JavaScript компиляция не нужна, но для Java или Go этот шаг добавляет время и сложность. GitHub поддерживает инкрементальный анализ для PR-сканирования - точные метрики ускорения зависят от размера кодовой базы.
Ограничения:
- Время сканирования: 20–45 минут на среднем монорепо - это выталкивает CodeQL из PR-чеков в nightly или merge-to-main
- QL имеет крутой порог входа: написание кастомного запроса - дни, не минуты
- Официально поддерживаемые языки: C/C++, C#, Go, Java/Kotlin, JavaScript/TypeScript, Python, Ruby, Swift - PHP отсутствует (актуальный список - в документации GitHub CodeQL)
- Полный опыт (Copilot Autofix, PR-комментарии) привязан к GitHub
- Стоимость: бесплатен для публичных репо; для приватных - через GitHub Advanced Security, ориентировочно от $49/committer/month - актуальные цены на github.com/pricing
SonarQube - интеграция code quality и security
SonarQube совмещает code quality (баги, code smells, метрики сложности) с security-сканированием. Community Edition бесплатна, поддерживает 30+ языков и запускается на собственной инфраструктуре - полный контроль над исходным кодом.Quality gates - главная сила SonarQube: PR не может быть смержен, если не проходит определённые пороги по количеству и severity уязвимостей. Для команд, которым нужен один инструмент для quality и security с compliance-отчётами (SOC 2, ISO 27001), SonarQube - логичный выбор.
Ограничения:
- Первые две недели после внедрения уходят на включение и выключение правил, а не на фикс уязвимостей
- Community Edition не включает taint analysis и cross-function data flow - они доступны начиная с Developer Edition
- Время сканирования: 5–30 минут для средних проектов
- SCA (анализ зависимостей) отсутствует в ядре - нужны плагины или платные версии
- Требует выделенного сервера и базы данных: это операционные расходы на поддержку
- Стоимость Developer Edition: зависит от объёма LOC, актуальные цены на sonarsource.com/plans-and-pricing
Сравнение SAST инструментов: trade-offs и ограничения
| Критерий | Semgrep | CodeQL | SonarQube |
|---|---|---|---|
| Архитектура | Паттерн-матчинг + taint (Pro) | Семантический граф (реляционная БД) | Broad ruleset + taint (платные версии) |
| Время PR-сканирования | Секунды | 20–45 минут | 5–30 минут |
| False positives (из коробки) | Средний, быстро тюнится | Низкий | Высокий (по субъективным оценкам) |
| Кастомные правила | Простой синтаксис, минуты | QL - высокий порог, дни | XML/UI, средний порог |
| Diff-only сканирование | Нативно, по умолчанию | Incremental (GitHub Actions) | Branch analysis (платная версия) |
| Требует компиляции | Нет | Да (Java, Go, C/C++) | Нет |
| Self-hosted | Да (CLI) | Да (CLI + GitHub) | Да (сервер + БД) |
| IDE-интеграция | VS Code, IntelliJ | VS Code (через GHAS) | SonarLint (VS Code, IntelliJ) |
| SCA (зависимости) | Ограниченный (Supply Chain) | Нет | Через плагины / платные версии |
| Когда использовать | PR-чеки, команды 5–50 человек | Глубокий анализ, nightly, GitHub-native | Quality + security, enterprise compliance |
| Когда НЕ использовать | Нужен deep semantic analysis | Нужна скорость в PR, не GitHub, PHP | Быстрая обратная связь, ограниченный бюджет |
Настройка SAST правил в CI/CD без alert fatigue
Требования к окружению
- Semgrep CLI: любая ОС с Python 3.8+, 2 ГБ RAM, доступ в интернет для загрузки правил (или offline с локальным реестром). Установка:
pip install semgrepили Docker-образreturntocorp/semgrep - CodeQL CLI: Linux/macOS/Windows, 8 ГБ RAM (16 ГБ для крупных проектов), build tools для целевого языка. Установка: бинарь с GitHub или
codeql-actionв GitHub Actions - SonarQube Server: выделенный сервер 4 ГБ RAM минимум (8 ГБ рекомендуется), PostgreSQL, Java 17+. Для CI -
sonar-scannerCLI
Diff-only сканирование и baseline
Главная стратегия борьбы с alert fatigue - сканировать только изменённый код. Semgrep делает это из коробки:semgrep ci в контексте PR автоматически анализирует только diff. CodeQL в GitHub Actions поддерживает incremental analysis. SonarQube Community Edition не поддерживает branch analysis - каждый scan обрабатывает всю базу; branch analysis доступен начиная с Developer Edition.Вторая стратегия - baseline. При первом внедрении SAST в проект с 200K+ строк сканер обнаружит сотни findings. Показывать их все разработчикам - прямой путь к тому, что на алерты перестанут смотреть через день. Создайте baseline и настройте pipeline на показ только новых findings:
YAML:
# GitLab CI - Semgrep с baseline и severity-фильтром
semgrep:
image: returntocorp/semgrep
variables:
SEMGREP_APP_TOKEN: $SEMGREP_APP_TOKEN # требуется для --config=auto
script:
- semgrep ci --baseline-commit $CI_MERGE_REQUEST_DIFF_BASE_SHA
--config=auto --config=.semgrep/custom-rules.yml
--severity ERROR --json --output=results.json
rules:
- if: $CI_MERGE_REQUEST_ID
# Без SEMGREP_APP_TOKEN замените --config=auto на --config=p/security-audit
# $CI_MERGE_REQUEST_DIFF_BASE_SHA доступна только в merge_request pipeline
Снижение ложных срабатываний через severity и confidence
На PR-чеках блокируйте мердж только при severity ERROR; WARNING пускайте в advisory-режиме. Кастомные правила под ваш стек с severity ERROR будут ломать pipeline при находке, а community-правила с WARNING - информировать без блокировки.Пример кастомного правила Semgrep для детектирования небезопасного ГПСЧ (CWE-330, по классификации OWASP - A02:2021 Cryptographic Failures):
YAML:
rules:
- id: insecure-random-security-context
pattern-either:
- pattern: random.random()
- pattern: Math.random()
message: "Небезопасный ГПСЧ в security-контексте"
languages: [python, javascript]
severity: ERROR
metadata: { cwe: "CWE-330", owasp: "A02:2021" }
new_security_rating на A и отделите его от new_reliability_rating. Для CodeQL фильтрация происходит на уровне query suites: стандартный security-extended покрывает критичные классы уязвимостей с низким false positive rate; свои запросы выносите в отдельный suite с пометкой @severity error.Какой SAST инструмент под какую задачу: decision tree
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Такой стек детектирует инъекции (OWASP A03:2021), криптографические ошибки (A02:2021), проблемы целостности кода и зависимостей (A08:2021) и утечки credentials. Ни один из слоёв не дублирует другой и не создаёт шума.
Типичная причина жалоб на SAST - инструмент включён с дефолтами без тюнинга. Включить SonarQube с дефолтными правилами на кодовую базу в 300K строк и удивляться потоку алертов - это как включить IDS в promiscuous mode на магистральном канале и жаловаться на количество событий. Инструмент делает ровно то, что просили.
Но проблема глубже. По результатам одного из академических исследований (оценивавшего несколько инструментов на датасете реальных уязвимостей), SAST-инструменты детектировали малую долю от общего числа уязвимостей. Остальное - ручной ревью, DAST, пентест. Пока вендоры соревнуются в количестве поддерживаемых языков и AI-ассистентах для автофикса, фундаментальное ограничение никуда не делось: статический анализ видит код, а не поведение.
Мой подход за последние два года устоялся: Semgrep на каждый PR с 20–30 кастомными правилами под проект, CodeQL по ночам на main для глубокого анализа, SonarQube как dashboard для менеджмента и compliance. Три инструмента - три роли - ноль пересечений. Alert fatigue при такой расстановке исчезает не потому, что инструменты стали умнее, а потому, что каждый делает только свою работу. Кто не пробовал выстроить слоистый стек и всё ещё мучается с одним инструментом на все задачи - на форуме codeby.net есть тред с конфигами под конкретные стеки, там обсуждаем подобные схемы регулярно.