Когда я работал в одном стартапе, мы два месяца искали SQL-injection в production. Нашли случайно. Если бы тогда у нас была нормальная автоматизация безопасности, потратили бы пару часов, а не две смены отладки под продакшеном. Вот тогда я понял: SAST в pipeline — это не опция, а необходимость.
GitLab SAST (Static Application Security Testing) — это встроенный в CI/CD механизм, который сканирует код и ловит уязвимости ещё до того, как код попадёт в production. Не нужно никаких внешних сервисов, не нужно доплачивать за облако. Всё работает внутри твоего GitLab.
Давайте разберёмся, как это реально работает и почему это экономит кучу времени.
Что такое SAST и почему это важнее, чем кажется
SAST — это статический анализ кода. Робот читает твой исходник, ищет паттерны, которые потенциально опасны, и говорит: "Стоп, здесь может быть проблема". Ключевое слово — "может быть". SAST часто даёт ложные срабатывания, и это нормально.
Противоположность SAST — это DAST (Dynamic Application Security Testing). DAST запускает приложение и пытается его взломать: отправляет вредоносные данные, проверяет заголовки, смотрит, что будет. SAST быстрее, DAST точнее, но дороже в смысле вычислений.
В GitLab SAST работает прямо в pipeline. Ты коммитишь код, запускается merge request, и автоматически:
- Код сканируется на известные паттерны уязвимостей
- Результаты выводятся в UI GitLab
- Блокируется merge, если нашлись критичные проблемы (если ты так настроил)
По моему опыту, 70% команд, которые внедрили SAST, за первый месяц находят по 3-5 серьёзных проблем, о которых раньше не знали.
Как включить SAST в GitLab CI
Самый простой способ — добавить в .gitlab-ci.yml одну строку:
include:
- template: Security/SAST.gitlab-ci.yml
Вот и всё. При следующем push GitLab автоматически подключит сканеры для всех языков, которые ты используешь в проекте.
Полный минимальный .gitlab-ci.yml:
stages:
- test
- security
include:
- template: Security/SAST.gitlab-ci.yml
test:
stage: test
script:
- npm test
sast:
stage: security
GitLab сам определит, какой язык ты пишешь, и запустит подходящие сканеры. Поддерживает Python, JavaScript, Java, Go, C#, PHP, Ruby и ещё с десяток.
Но если ты хочешь больше контроля — можешь настроить детальнее:
include:
- template: Security/SAST.gitlab-ci.yml
variables:
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
SAST_BANDIT_LEVEL: 2
sast:
stage: security
allow_failure: false
Здесь:
SAST_EXCLUDED_PATHS— исключаем тесты и временные файлы (не нужно сканировать)SAST_BANDIT_LEVEL— уровень строгости для Python (от 1 до 4)allow_failure: false— если нашлись уязвимости, pipeline падает
Какие уязвимости ловит GitLab SAST
Честно? Большинство разработчиков думают, что SAST ловит только очевидные баги. На самом деле спектр шире.
SQL-injection — классика жанра:
# Плохо
user_id = request.args.get('id')
query = f"SELECT * FROM users WHERE id = {user_id}"
result = db.execute(query)
# SAST это поймает
SAST видит, что в SQL-запрос вставляется пользовательский ввод напрямую. Это красный флаг.
Command injection — когда передаёшь параметры в системные команды:
# Плохо
filename = request.args.get('file')
os.system(f"cat {filename}")
# SAST это видит
Если злоумышленник передаст file=secret.txt; rm -rf /, будет беда. SAST ловит такие паттерны.
Использование небезопасных функций:
# Плохо — eval() опасен
code = request.args.get('code')
result = eval(code)
# SAST это поймает и скажет: используй ast.literal_eval() или другой способ
Жёсткие пароли в коде:
# Плохо
DB_PASSWORD = "super_secret_123"
API_KEY = "sk-1234567890abcdef"
# SAST это поймает
SAST ловит регулярные выражения, которые похожи на секреты. Очень полезно, потому что люди часто забывают, что залили пароль в git.
Unsafe deserialization — десериализация JSON/pickle из ненадёжных источников:
# Плохо
import pickle
data = request.data
obj = pickle.loads(data) # SAST: опасно!
# Плохо
import json
user_input = request.args.get('data')
obj = json.loads(user_input)
eval(obj) # Если дальше это обрабатывается опасно
XXE (XML External Entity) — когда парсишь XML без защиты:
# Плохо
import xml.etree.ElementTree as ET
xml_data = request.data
tree = ET.fromstring(xml_data) # Без защиты от XXE
Weak cryptography — использование старых алгоритмов:
# Плохо
import hashlib
password_hash = hashlib.md5(password).hexdigest()
# Нужно использовать bcrypt или argon2
По-хорошему, за первый запуск SAST на среднем проекте можно найти 5-15 таких проблем. Большинство из них вполне реальные уязвимости.
Интеграция с GitLab UI и результаты
После того как SAST отработает, результаты видны в нескольких местах:
В merge request — инлайн-комментарии прямо на коде:
На строке 42:
⚠️ SQL Injection - User input directly concatenated in SQL query
Severity: High
CWE: CWE-89
В Security tab проекта — полный список всех найденных уязвимостей с историей:
Critical: 2
High: 5
Medium: 12
Low: 8
В artifacts — JSON с подробными отчётами (если нужно обработать программно).
Можешь настроить, чтобы pipeline блокировался, если нашлись уязвимости выше определённого уровня. Например:
sast:
stage: security
allow_failure: false # Pipeline падает, если есть High или выше
Или с более тонкой настройкой через Policy:
sast:
stage: security
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
allow_failure: false
- allow_failure: true
Здесь: в main branch блокируем, в feature branch только предупреждаем.
Практические примеры настройки
Вот реальный конфиг, который я использую на проектах:
stages:
- build
- test
- security
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
variables:
SAST_EXCLUDED_PATHS: "tests,spec,node_modules,vendor"
SAST_EXCLUDED_ANALYZERS: "eslint" # Используем свой linter
SECURE_LOG_LEVEL: "debug"
sast:
stage: security
artifacts:
reports:
sast: gl-sast-report.json
expire_in: 30 days
allow_failure: false
only:
- merge_requests
- main
- develop
dependency_scanning:
stage: security
allow_failure: true # Только предупреждаем о уязвимостях в зависимостях
Что здесь:
- Исключаем тесты и node_modules от сканирования (зачем проверять чужой код?)
- Отключаем eslint, потому что у нас свой linter в проекте
- Сохраняем отчёты в артефакты (на случай, если нужно проанализировать позже)
- Блокируем merge на SAST, но только предупреждаем на dependency scanning
GitLab CI SAST vs. другие инструменты
Часто спрашивают: "А может быть, лучше использовать SonarQube или Checkmarx?"
По-хорошему, GitLab SAST — это не замена, это база. Вот сравнение:
GitLab SAST:
- Бесплатно (включено в любой план)
- Встроено в pipeline
- Быстро (сканирует за 1-3 минуты на среднем проекте)
- Хватает для 80% задач
SonarQube:
- Платно (от 5000 евро в год)
- Точнее, более детальный анализ качества кода
- Красивый dashboard с метриками
- Если нужна полная картина по всему проекту
Checkmarx:
- Очень дорого (от 20k в год)
- Поиск очень глубокий, но много ложных срабатываний
- Для крупных корпораций
На практике: начни с GitLab SAST, если её недостаточно — добавь SonarQube. Checkmarx берут только крупные компании с бюджетом.
Типичные ошибки при внедрении SAST
Ошибка 1: Включил SAST и заблокировал все merge requests
Правильно: сначала запусти в режиме allow_failure: true неделю-две, дай команде разобраться с существующими проблемами, потом включи блокировку.
Ошибка 2: Исключил слишком много путей
Видел проект, где исключили src, потому что "там слишком много ложных срабатываний". Вместо этого нужно настроить правила конкретнее или обновить версию сканера.
Ошибка 3: Игнорируешь все warnings
Если в SAST появляются жалобы, которые ты помечаешь как "false positive" — не просто игнорируй, добавь их в whitelist:
sast:
variables:
SAST_EXCLUDED_PATHS: "..."
Это поможет избежать спама в следующих запусках.
Ошибка 4: Не обновляешь версии сканеров
GitLab регулярно выпускает обновления для SAST-сканеров. Новые версии ловят новые уязвимости. Обновляй хотя бы раз в квартал.
Как интегрировать SAST с другими инструментами
Если у тебя уже есть система управления уязвимостями (например, Jira или Linear для трекинга), можешь автоматизировать создание задач:
sast:
artifacts:
reports:
sast: gl-sast-report.json
create_issues:
stage: security
image: alpine:latest
script:
- |
# Парсим JSON отчёта
cat gl-sast-report.json | jq '.vulnerabilities[] |
"curl -X POST https://jira.company.com/rest/api/2/issue
-d {\"fields\": {\"project\": \"SEC\", \"summary\": .name}}"'
dependencies:
- sast
only:
- merge_requests
Это уже более специфичный пример, но идея понятна: можешь захватить результаты SAST и отправить их в свою систему.
Что дальше после SAST
SAST — это только первый слой защиты. По-хорошему, нужна комбо:
- SAST (статический анализ) — ловит очевидные проблемы в коде
- Dependency scanning — проверяет, не используешь ли ты библиотеки с известными уязвимостями
- DAST (динамический анализ) — запускает приложение и тестирует его
- Container scanning — сканирует Docker-образы на уязвимости
- License scanning — проверяет, что используемые библиотеки имеют совместимые лицензии
В GitLab всё это встроено. Просто добавляй шаблоны в .gitlab-ci.yml:
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Security/DAST.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
И у тебя появится полная защита.
Если SAST в GitLab кажется тебе недостаточным или ты хочешь добавить слой code review поверх автоматизации — попробуй Distiq. Это AI-бот для code review, который работает в GitLab, GitHub и GitVerse. Он ловит не только уязвимости, но и архитектурные проблемы, проблемы с производительностью, нарушения стиля кода. Настраивается за пару минут, интегрируется через webhook. Российский сервис, данные остаются в стране.
Начни с встроенного SAST — это база. Добавь Distiq, если н
