На одном проекте в 2019-м мы выкатили релиз в пятницу вечером. К понедельнику сервис взломали. SQL-инъекция через форму поиска — классика. Команда честно писала юнит-тесты, код-ревью делали. Но никто не заметил, что request.GET.get('q') улетает прямо в.raw()-запрос.
После этого случая мы внедрили SAST. А через полгода — DAST. И это две большие разницы.
Что такое SAST и почему это первый уровень защиты
SAST — Static Application Security Testing. Анализирует исходный код без его запуска. Сканирует, ищет паттерны уязвимостей, выдаёт список проблем.
Принцип простой: если в коде есть eval(user_input), SAST это найдёт. Не нужно деплоить, не нужно гонять тесты. Запустил сканер — получил отчёт.
SAST ловит:
- SQL-инъекции
- XSS в серверном рендеринге
- Hardcoded credentials (пароли в коде, API-ключи)
- Уязвимости десериализации
- Небезопасные конфигурации
Вот типичный пример, который SAST находит мгновенно:
# Уязвимый код — SQL injection
def get_user(request):
user_id = request.GET.get('id')
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
return cursor.fetchone()
SAST-сканер подсветит строку с execute и скажет: "передача непроверенных данных в SQL-запрос". Правильно скажет.
Как это чинить — тоже известно:
# Безопасный вариант
def get_user(request):
user_id = request.GET.get('id')
cursor.execute("SELECT * FROM users WHERE id = %s", [user_id])
return cursor.fetchone()
Популярные SAST-инструменты: SonarQube, Checkmarx, Semgrep, Bandit (для Python), ESLint с security-плагинами.
Главная проблема SAST — false positives. Много false positives. На том же проекте после внедрения Bandit мы получили 200+ предупреждений. Из них реальных уязвимостей — три. Остальное — легитимный код, который сканер не понял.
Но это решаемо. Настраиваешь правила, исключаешь ложные срабатывания, добавляешь аннотации. Через месяц пайплайн начал показывать только то, что реально важно.
DAST: когда нужно увидеть, как код ведёт себя в бою
DAST — Dynamic Application Security Testing. Работает по-другому: сканирует работающее приложение. Отправляет запросы, смотрит ответы, ищет уязвимости в рантайме.
SAST не видит проблем конфигурации сервера. DAST — видит. SAST не знает, как приложение отреагирует на нестандартный ввод. DAST проверит.
Типичный кейс для DAST — уже развернутое приложение, которое кто-то пентестит. Но можно и нужно запускать DAST автоматически в пайплайне перед релизом.
Что ловит DAST:
- SQL-инъекции в runtime
- XSS, которые сработают в браузере
- Проблемы с аутентификацией и сессиями
- Небезопасные HTTP-заголовки
- Exposure чувствительных данных в ответах
- Уязвимости в API
Пример: DAST-сканер OWASP ZAP находит открытый эндпоинт администратора. SAST этого не увидит — код валидный, просто забыли закрыть доступ middleware.
# Пример конфигурации DAST в GitLab CI
stages:
- test
- dast
dast:
stage: dast
image: owasp/zap2docker-stable
script:
- zap-baseline.py -t https://staging.example.com -r dast_report.html
artifacts:
paths:
- dast_report.html
Запустили, получили отчёт, увидели, что /admin/debug доступен без авторизации. Быстро чиним.
Минус DAST — нужен работающий стенд. И время. Полное сканирование может занять 10-30 минут. В быстрых циклах CI/CD это напрягает.
SCA: третий игрок, который часто забывают
SAST DAST SCA — три кита безопасности в DevOps. SCA — Software Composition Analysis. Проверяет зависимости.
В modern-разработке 70-80% кода — это зависимости. npm packages, pip wheels, go modules. И в них тоже есть уязвимости.
Помните Log4Shell? Уязвимость в библиотеке логирования, которая была в большинстве Java-проектов. SAST её не найдёт — проблема не в вашем коде. DAST найдёт, если знает, что искать. А SCA скажет сразу: "у вас log4j 2.14.1, обновите до 2.17.0".
# Пример отчёта SCA-инструмента
npm audit
# found 3 vulnerabilities (1 low, 1 moderate, 1 critical)
# - lodash <4.17.21: prototype pollution
# - node-fetch <2.6.7: SSRF via redirect
Инструменты SCA: Dependabot, Snyk, OWASP Dependency-Check, npm audit, pip-audit.
Внедряется элементарно:
# GitLab CI + Dependency Check
dependency_check:
image: owasp/dependency-check
script:
- /usr/share/dependency-check/bin/dependency-check.sh
--scan ./
--format HTML
--out report.html
artifacts:
paths:
- report.html
Теперь каждый MR проверяется на известные CVE в зависимостях.
Типичные уязвимости и как их ловить
По моему опыту, топ проблем в российских проектах:
SQL-инъекции. До сих пор встречаются в каждом третьем легаси-проекте. SAST ловит отлично. DAST подтверждает. Чинится параметризованными запросами.
XSS. Особенно в проектах с серверным рендерингом. React/Vue экранируют автоматически, но если используете dangerouslySetInnerHTML или аналоги — welcome. SAST находит паттерны, DAST проверяет exploitation.
Hardcoded secrets. API-ключи, пароли от БД, токены — всё это коммитят в репозиторий. Регулярно. SAST ищет паттерны вида password = "...", api_key = "...". Можно настроить git-secrets как pre-commit hook.
# Git-secrets в действии
git commit -m "Add config"
# ERROR: Matched forbidden pattern: AWS_SECRET_ACCESS_KEY
Path traversal. Когда open(request.GET['file']) открывает не только файлы из нужной директории. SAST находит, DAST подтверждает запросами вида ../../../etc/passwd.
Insecure deserialization. Python pickle, Java serialization — классика. SAST подсветит pickle.loads(user_data) как критическую проблему.
Как внедрить в пайплайн и не сойти с ума
Честно? Большинство команд бросают безопасность после первой недели. Слишком много шума, слишком мало сигнала.
Правильный подход — постепенный.
Начните с SAST. Возьмите Semgrep или Bandit (бесплатно, быстро, настраивается). Настройте на блокировку только critical и high. Medium и low — в информативный режим.
# Минимальный SAST в GitLab
include:
- template: Security/SAST.gitlab-ci.yml
variables:
SAST_EXCLUDED_ANALYZERS: "bandit,semgrep"
SAST_SEMGREP_RULESET: "p/security-audit"
Настройте исключения. Пробегитесь по false positives, добавьте аннотации в код. Через 2-3 недели SAST начнёт приносить пользу.
Потом добавьте SCA. Это даст быстрые победы — обновите пару зависимостей, закроете реальные CVE.
DAST — последним. Нужно поднять стенд, настроить сканер, ждать результаты. Но DAST даёт уверенность, что приложение не развалится при реальной атаке.
Рекомендация
Когда внедрили SAST и DAST, следующий шаг — автоматизировать code review с фокусом на безопасность. Это не заменяет специализированные инструменты, но добавляет ещё один слой защиты.
Distiq — наш российский сервис AI code review для GitLab, GitHub и GitVerse. Он анализирует MR/PR и находит не только баги, но и потенциальные уязвимости. Интегрируется за минуту через webhook. Серверы в РФ, данные никуда не уходят. Достойная альтернатива CodeRabbit для тех, кто работает с чувствительными проектами.
