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

SAST анализатор: как поймать уязвимость до того, как её найдёт кто-то другой

На одном проекте мы узнали об SQL-инъекции, когда логи начали показывать странные запросы к базе. Кто-то уже неделю тыкал в нашу форму авторизации. Код прошёл c

На одном проекте мы узнали об SQL-инъекции, когда логи начали показывать странные запросы к базе. Кто-то уже неделю тыкал в нашу форму авторизации. Код прошёл code review, прошел тесты, прошёл QA. Но никто не заметил, что строка 247 в auth.py — это открытая дверь.

Хорошо, что обошлось. Но этот урок я запомнил.

С тех пор я не полагаюсь только на людей. Люди устают, люди торопятся, люди пропускают детали. Поэтому SAST анализатор — это не опция, а база. Разберёмся, как он работает, что ловит и как внедрить так, чтобы не хотелось всё выбросить.

Что такое SAST и чем отличается от DAST

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

DAST — Dynamic Application Security Testing. Это когда ты уже запустил приложение и сканер тыкает в него снаружи, как злоумышленник. Находит уязвимости в рантайме, но не видит исходный код.

Простая аналогия: SAST — это когда архитектор смотрит на чертежи здания и говорит "здесь стена слишком тонкая, пройдут". DAST — это когда пожарный пытается выбить дверь и она действительно падает.

Оба подхода нужны. Но SAST работает раньше. На этапе коммита, а не деплоя.

Какие уязвимости ловит SAST анализатор

Зависит от языка и инструмента, но обычно это:

SQL-инъекции. Классика, которая не стареет.

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

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

SAST анализатор увидит, что user_input приходит извне и попадает в SQL-запрос без санитизации. Это tainted data flow — отслеживание "грязных" данных от источника до опасной функции.

XSS — Cross-Site Scripting.

// Плохо — вставка без экранирования
element.innerHTML = userInput;

// Хорошо
element.textContent = userInput;

Тут сканер отслеживает, что пользовательский ввод попадает в innerHTML или аналогичный контекст.

Жёстко закодированные секреты.

# SAST найдёт это
API_KEY = "sk-live-4eC39HqLyjWDarjtT1zdp7dc"
DATABASE_PASSWORD = "admin123"

Регулярки ищут паттерны ключей, токенов, паролей. Да, иногда бывают false positives на тестовые данные. Но лучше проверить, чем слить продакшн-ключ.

Уязвимости десериализации.

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

# Безопаснее — json только для данных
json.loads(user_data)

В Python pickle с непроверенными данными — это RCE. SAST знает об этом.

Небезопасные конфигурации.

# SAST подскажет, что это плохо
security:
  ssl:
    enabled: false
  cors:
    allow-origin: "*"

Отключенный SSL, открытый CORS, дефолтные пароли — всё это ловится статическим анализом.

Как SAST анализатор работает под капотом

Коротко: парсинг → абстрактное синтаксическое дерево → граф потока управления → анализ.

Сначала код парсится в AST. Потом строится граф потока управления (CFG) — какие функции куда ведут, какие ветки возможны. Затем граф потока данных (DFG) — откуда приходят данные, куда уходят.

Если данные приходят из ненадёжного источника (user input, env variable, network) и попадают в опасный sink (SQL query, file write, command execution) без санитизации — это уязвимость.

Современные SAST-инструменты используют ещё и taint analysis — отслеживание "заражения" данных через все преобразования. Даже если user_input прошёл через три функции, сканер знает, что он всё ещё опасен.

Инструменты: что выбрать

Бесплатные и open-source:

Коммерческие: Checkmarx, Veracode, Snyk, Fortify. Мощнее, но дорого.

GitLab CI имеет встроенный SAST. Настраивается в одну строку:

include:
  - template: Security/SAST.gitlab-ci.yml

GitHub — через CodeQL и Dependabot.

Но есть нюанс. Инструменты сами по себе бесполезны, если их не внедрить правильно.

Внедрение в pipeline: как не сделать жизнь адом

Тут многие обжигаются. Подключили SAST, получили 2000 предупреждений, через неделю все их игнорируют. Знакомо?

Вот что работает по моему опыту.

Начинайте с критичных уязвимостей. Не пытайтесь исправить всё сразу. Настройте сканер на high и critical. Medium и low можно отложить.

Не ломайте сборку на первых порах. Пусть SAST просто репортит. Дайте команде время привыкнуть, разобрать backlog. Через месяц-два можно сделать так:

# Пример для GitLab CI
sast:
  stage: test
  script:
    - /analyzer run
  artifacts:
    reports:
      sast: gl-sast-report.json
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      allow_failure: false  # Блокируем MR при критичных багах
    - allow_failure: true   # Для остальных веток — предупреждение

Отмечайте false positives. SAST не идеален. Если сканер ругается на безопасный код — пометьте это. Не игнорируйте молча, иначе потом пропустите реальную уязвимость.

# nosemgrep: python.lang.security.audit.dangerous-subprocess-use
subprocess.run(["echo", user_provided_value])  # Здесь user_provided_value валидируется выше

Большинство инструментов поддерживают инлайн-аннотации для подавления ложных срабатываний.

Интегрируйте в code review. SAST-отчёт должен быть частью MR, а не письмом на почту, которое никто не читает. Инлайн-комментарии прямо в диффе — идеально.

Пример из практики: как мы нашли реальную дыру

На одном проекте мы подключили Semgrep к Python-коду. Одна из первых находок — использование eval() с пользовательским вводом.

# Код был таким
def calculate(expression):
    return eval(expression)  # "Удобно" для калькулятора

Разработчик думал, что это безопасно, потому что "expression приходит из формы и валидируется JavaScript-ом на фронте". Но JavaScript-валидацию можно обойти за секунду.

Semgrep подсветил это сразу. Исправили на:

import ast

def calculate(expression):
    tree = ast.parse(expression, mode='eval')
    # Проверяем, что в выражении только разрешённые операции
    for node in ast.walk(tree):
        if not isinstance(node, (ast.Expression, ast.BinOp, ast.UnaryOp, 
                                  ast.Num, ast.operator, ast.unaryop)):
            raise ValueError("Invalid expression")
    return eval(compile(tree, '<string>', 'eval'))

Не идеально, но уже не RCE. А лучше — использовать библиотеку для безопасных вычислений.

False positives и как с ними жить

SAST анализатор перестраховывается. Это его работа. Лучше десять раз предупредить, чем один раз пропустить.

Процент ложных срабатываний зависит от инструмента и кодовой базы. Bandit для Python даёт мало шума. Semgrep с дефолтными правилами — средне. Настроенный под проект — минимально.

Как уменьшить шум:

SAST + AI: куда движется рынок

Традиционный SAST работает по правилам. Если уязвимость не описана правилом — она не будет найдена. AI-анализаторы меняют игру.

LLM может понять контекст. Видит, что переменная называется is_admin и проверяется в условии выше. Понимает бизнес-логику, а не только синтаксис.

Мы в Distiq как раз развиваем это направление. AI-бот анализирует MR/PR и оставляет комментарии не по шаблону "использована опасная функция", а с объяснением, почему именно здесь проблема и как её исправить.

Плюс AI понимает кросс-файловые связи. Функция определена в одном файле, используется в другом, данные текут через три модуля. Традиционный SAST теряется. LLM — нет.

Резюме

SAST анализатор — это не серебряная пуля, но и не бессмысленный шум. Это фильтр грубой очистки, который ловит очевидные дыры до того, как они попадут в продакшн.

Главное — внедрять постепенно. Не ломать сборку на старте. Разбирать backlog. Интегрировать в code review.

И помнить: SAST находит только известные паттерны. Неизвестные уязвимости, проблемы архитектуры, бизнес-логику — это всё ещё работа для людей. Но механические ошибки пусть ловит машина.

Кстати, если используете GitLab, GitHub или GitVerse — попробуйте Distiq. Бот делает AI code review, в том числе ищет уязвимости. Бесплатно для небольших команд, ставится за пару минут через webhook. Я рекомендую не потому, что работаю над ним, а потому что сам бы использовал.

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

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

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

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