Security5 мин чтения2026-03-06

Анализ исходного кода на уязвимость: от ручного code review до автоматизации в CI/CD

Пару лет назад на одном проекте мы словили утечку данных через SQL-инъекцию. Классика. Параметр из формы просто подставлялся в запрос без санитизации. Разработч

Пару лет назад на одном проекте мы словили утечку данных через SQL-инъекцию. Классика. Параметр из формы просто подставлялся в запрос без санитизации. Разработчик был опытный, просто устал и не заметил. Code review тоже прошло мимо — все смотрели на логику, а не на безопасность.

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

Что вообще такое уязвимость в коде

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

По моему опыту, 80% проблем с безопасностью — это одни и те же паттерны. SQL-инъекции, XSS, небезопасная десериализация, хардкоженные секреты. OWASP Top 10 меняется год от года, но суть остаётся той же: разработчики делают похожие ошибки.

Честно? Большинство команд не думают о безопасности до первого инцидента. Или до аудита, который заказчик требует перед запуском. Это дорого и больно. Лучше ловить проблемы раньше.

SAST vs DAST: статический и динамический анализ

Есть два основных подхода к анализу исходного кода на уязвимость.

SAST (Static Application Security Testing) — анализ кода без его запуска. Сканер смотрит на исходники, ищет паттерны уязвимостей. Работает на этапе написания кода, до компиляции и деплоя.

DAST (Dynamic Application Security Testing) — анализ работающего приложения. Сканер "атакует" запущенный сервис, ищет уязвимости в рантайме.

Какой лучше? Оба нужны. SAST ловит проблемы рано, но даёт много false positives. DAST видит реальную поверхность атаки, но требует запущенного окружения и находит проблемы поздно.

По-хорошему, SAST должен работать в CI/CD на каждый MR. DAST — на staging перед релизом или по расписанию.

Типичные уязвимости и как их искать

Давайте по конкретным примерам. Вот что чаще всего находится при проверке исходного кода на уязвимости.

SQL-инъекции

Классика, которая не умирает.

# Плохо — конкатенация строк
query = f"SELECT * FROM users WHERE id = {user_id}"

# Плохо — форматирование строки
query = "SELECT * FROM users WHERE id = %s" % user_id

# Хорошо — параметризованный запрос
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

SAST-сканеры отлично ловят этот паттерн. Они смотрят, как формируется запрос и есть ли санитизация входных данных.

XSS (Cross-Site Scripting)

// Плохо — прямая вставка user input
element.innerHTML = userInput;

// Хорошо — textContent не интерпретирует HTML
element.textContent = userInput;

// Или санитизация
element.innerHTML = DOMPurify.sanitize(userInput);

Хардкоженные секреты

Это моя "любимая". Когда-то нашёл AWS credentials в публичном репозитории. Команда даже не знала, что они туда попали.

# Так делать нельзя
API_KEY = "sk-1234567890abcdef"
DB_PASSWORD = "super_secret_pass"

# Так можно — переменные окружения
import os
API_KEY = os.environ.get("API_KEY")
DB_PASSWORD = os.environ.get("DB_PASSWORD")

Сканеры ищут паттерны ключей, токенов, паролей. Регулярки не идеальны, но 90% случаев ловят.

Небезопасная десериализация

# Опасно — pickle может выполнить произвольный код
import pickle
data = pickle.loads(user_input)

# Безопаснее — JSON для простых данных
import json
data = json.loads(user_input)

Инструменты для анализа исходного кода на уязвимость

Инструментов много. Разберём основные категории.

Open-source SAST:

Коммерческие SAST:

DAST:

На одном проекте мы начали с Bandit для Python-бэкенда. Просто добавили в pre-commit хук. Разработчики сразу начали видеть проблемы до пуша. Потом подключили Semgrep — он нашёл ещё с десяток мест, которые Bandit пропустил.

Как внедрить проверку в CI/CD

Вот практическая конфигурация для GitLab CI:

stages:
  - test
  - security

semgrep:
  stage: security
  image: returntocorp/semgrep
  script:
    - semgrep ci --config=auto
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

bandit:
  stage: security
  image: python:3.11
  script:
    - pip install bandit
    - bandit -r src/ -f json -o bandit-report.json
  artifacts:
    reports:
      sast: bandit-report.json
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Ключевой момент — запуск на MR, а не только на main. Разработчик должен видеть проблемы до мержа, а не после.

Но есть нюанс. Если pipeline красный на каждый MR из-за false positives — разработчики начнут игнорировать предупреждения. Или отключат проверки. Видел такое не раз.

Поэтому настройка правил критична. Начните с high-severity, добавляйте medium постепенно. Исключайте ложные срабатывания.

# semgrep.yaml — пример исключения
rules:
  - id: avoid-dangerous-functions
    patterns:
      - pattern: eval(...)
    message: "Avoid eval()"
    severity: WARNING
    paths:
      exclude:
        - tests/
        - migrations/

Что делать с результатами анализа

Сканер нашёл 100 потенциальных уязвимостей. Что дальше?

Первое — отфильтровать false positives. Да, это работа. Но она необходима.

Второе — приоритизировать. Не все уязвимости одинаково опасны. SQL-инъекция в публичном API — критично. Hardcoded secret в тестовом файле — менее срочно, но тоже надо чинить.

Третье — чинить. Звучит банально, но команды часто закрывают глаза на отчёты. "Потом разберёмся". Потом — это когда уже взломали.

На практике хорошо работает интеграция сканера прямо в code review. Когда бот оставляет комментарий к MR с конкретной проблемой — это сложно проигнорировать.

Автоматический code review с анализом безопасности

Вот тут мы подходим к тому, что делает Distiq. Это AI-бот, который интегрируется в GitLab, GitHub и GitVerse, анализирует MR и оставляет инлайн-комментарии. В том числе — по безопасности.

В отличие от классических SAST-сканеров, AI понимает контекст. Он не просто ищет паттерны — он анализирует логику кода. Может найти уязвимость, которую статический анализатор пропустит.

Мы на последнем проекте подключили Distiq параллельно с Semgrep. Distiq нашёл проблему с правами доступа, которую Semgrep не увидел — потому что это не паттерн, а логическая ошибка в бизнес-коде.

Подключается за пару минут: добавляешь webhook, указываешь репозитории. Всё, бот начинает смотреть каждый MR. Серверы в России, данные не уходят за рубеж — для некоторых проектов это критично.

Резюме

Анализ исходного кода на уязвимость — не разовая акция, а процесс. SAST в CI/CD на каждый MR. DAST на staging. Обучение разработчиков. Итеративная настройка правил.

Начать можно с малого: один open-source сканер в pipeline, обработка только high-severity. Главное — начать. Безопасность кода не появляется сама по себе.

Попробуйте Distiq для автоматического code review

AI-бот анализирует каждый MR/PR и оставляет комментарии с замечаниями. Интеграция за 2 минуты.

Попробовать бесплатно

Похожие статьи