Перейти к содержимому

Собеседование AppSec-инженера: почему спрашивают про git blame и git bisect

Собеседование AppSec-инженера: почему спрашивают про git blame и git bisect
Время чтения: 10 мин.

На код-ревью перед релизом я наткнулся на строку verify=False в HTTP-клиенте продакшн-сервиса — кто-то отключил проверку TLS-сертификата. Команда git blame -w показала: строку добавил разработчик 8 месяцев назад в коммите с сообщением «fix CI tests». Через 40 секунд у меня был контекст, мотив и масштаб проблемы — а SAST-сканер (инструмент статического анализа кода) это нашёл только сейчас. Вот такую скорость расследования и проверяют на собеседовании AppSec-инженера, когда задают вопросы про git. И нет, спрашивают не про GitHub Flow.

Что проверяют на собеседовании AppSec-инженера, когда спрашивают про git

GitHub Flow, GitFlow, trunk-based development — стратегии ветвления. Любой мидл-разработчик их знает. На собеседовании security engineer проверяют другое: умеете ли вы пользоваться git как инструментом расследования.

Разница между «знать workflow» и «уметь расследовать» — как между водителем и следователем ДТП. Оба ездят на машине, но один едет по маршруту, а другой восстанавливает картину аварии по следам на асфальте. В AppSec это называют code archaeology (код-археология) или git forensics — восстановление событий по цифровым следам в репозитории.

Что на самом деле стоит за типичными вопросами:

  • git blame — можете ли вы быстро установить, кто, когда и зачем изменил конкретную строку кода. В контексте безопасности: кто добавил hardcoded секрет, кто отключил валидацию входных данных, кто убрал CSP-заголовок (Content Security Policy — HTTP-заголовок, ограничивающий загрузку ресурсов на странице).
  • git bisect — можете ли вы найти конкретный коммит, который сломал security-тест или внёс регрессию. Это бинарный поиск по истории коммитов: git делит историю пополам и за log₂(n) шагов находит «плохой» коммит. Для 1000 коммитов — примерно 10 проверок вместо тысячи.
  • git log -S (pickaxe-поиск) — можете ли вы найти коммит, в котором определённая строка (пароль, API-ключ, опасная функция) появилась или исчезла из кодовой базы.

Все три инструмента решают задачи, с которыми AppSec сталкивается ежедневно: анализ git истории на уязвимости, поиск утечек в git репозитории, расследование инцидентов. Знание branching-стратегии ни одну из этих задач не закрывает.

Если перевести на язык MITRE ATT&CK (открытая база тактик и техник атак; T-коды вроде T1552 — её идентификаторы): секреты в коде — техника Credentials In Files (T1552.001, тактика Credential Access). Атакующие целенаправленно ищут учётные данные в файлах и git-истории. Если AppSec-инженер не умеет делать то же самое в своём репозитории — он проигрывает атакующему в скорости. А техника Code Repositories (T1213.003, тактика Collection) описывает сценарий, когда злоумышленник собирает информацию из репозиториев — включая удалённые ветки и «забытые» коммиты.

git blame для безопасности: расследование вместо обвинения

git blame показывает для каждой строки файла: хеш коммита, автора, дату и содержимое. В базовом виде — git blame path/to/file.py — работает, но на appsec собеседовании ждут понимания глубже.

Проблема базового blame: он часто показывает автора последнего форматирования (прогон линтера, переименование переменной), а не того, кто написал уязвимую логику. Чтобы добраться до реального автора, нужны флаги:

-w игнорирует изменения пробелов. Прогон black или prettier по всей кодовой базе «затирает» реальную историю blame — флаг -w пробивается сквозь это. -M обнаруживает строки, перемещённые внутри файла: если разработчик переместил функцию, blame без -M покажет его, а не реального автора логики. -C обнаруживает строки, скопированные из других файлов. Уязвимый код часто «путешествует» через copy-paste.

Комбинация git blame -w -M -C — то, что опытный AppSec-инженер использует по умолчанию. Упоминание на собеседовании сразу отличает практика от человека, который прочитал первые два абзаца документации.

Как найти автора уязвимого кода через git blame

Допустим, Semgrep или CodeQL (SAST-инструменты, которые ищут уязвимые паттерны в исходном коде) нашёл SQL-инъекцию в файле api/views.py на строках 42-60.

Чтобы понять контекст — кто это написал, когда и в рамках какой задачи — запускаем blame с фильтрацией по конкретным строкам:

# blame с полным набором флагов, ограниченный строками 42-60
git blame -w -M -C -L 42,60 api/views.py
# полный контекст коммита: diff, сообщение, все изменённые файлы
git show abc1234

В выводе blame для каждой строки — хеш коммита, имя автора и дата. Ищите коммит, в котором появилась конкатенация SQL-запроса вместо параметризованного. Затем git show <hash> покажет сообщение коммита, и часто оно объясняет мотивацию: «hotfix для продакшна», «обход ограничения ORM». Это и есть root cause.

Ещё один приём — файл .git-blame-ignore-revs. Это список хешей «шумных» коммитов (массовое форматирование, миграция стиля), которые blame будет пропускать. Файл размещается в корне репозитория. GitHub и GitLab поддерживают его в веб-интерфейсе — после добавления вся команда видит «чистый» blame. На собеседовании достаточно упомянуть этот файл и объяснить, зачем он нужен — это показывает, что вы работали с blame на реальных проектах, а не в учебном репозитории с тремя коммитами.

Ключевой принцип из документации CloudBees: «git blame — для случаев, когда вы знаете, где искать». Знаете файл и строку — blame. Не знаете — нужен другой инструмент.

git bisect — поиск уязвимости бинарным поиском

git bisect решает ситуацию, когда вы знаете: security-тест проходил неделю назад, а сейчас падает. Между этими точками — 200 коммитов. Проверять каждый вручную — часы работы. bisect найдёт виновный коммит за ~8 шагов.

Типичная для AppSec ситуация: кто-то сломал CSP-заголовок, убрал rate limiting, изменил конфигурацию CORS (Cross-Origin Resource Sharing — политика браузера, контролирующая, какие домены могут обращаться к вашему API). Security regression обнаружили не сразу, и теперь нужно найти точный коммит среди сотен.

Автоматический bisect для security-регрессий

Предпосылка: вы в корне git-репозитория, есть тест или скрипт, который воспроизводит проблему.

# Ручной bisect: отвечаете good/bad на каждом шаге
git bisect start
git bisect bad                        # HEAD содержит баг
git bisect good v2.1.0                # здесь бага не было
# git переключает на средний коммит — проверяете — git bisect good/bad
git bisect reset                      # возврат на исходную ветку

# Автоматический: git сам прогоняет тест на каждом шаге
git bisect start HEAD v2.1.0
git bisect run pytest tests/test_csp_header.py -x

При ручном bisect git переключает рабочую директорию на коммит посередине диапазона. Проверяете — баг есть? Отвечаете git bisect bad или git bisect good. Через 7-10 итераций git выводит: first bad commit is ... — точный коммит, автор, diff.

При автоматическом bisect передаёте скрипт через git bisect run. Тест должен возвращать код 0 для «хорошего» коммита и ненулевой для «плохого». Git сам прогонит бинарный поиск без вашего участия. Код 125 говорит bisect пропустить коммит — полезно, когда коммит не компилируется.

На собеседовании ключевое — объяснить, что bisect работает, когда вы не знаете, где искать. Знаете файл — blame. Не знаете даже файл, но можете сформулировать тест «работает / не работает» — bisect.

По данным Atlassian, при 20 000 коммитов bisect находит виновный коммит за ~15 проверок. Для AppSec-инженера, расследующего regression bug, это часы сэкономленного времени.

Секреты в git истории: поиск утечек в репозитории

Одна из главных задач AppSec — поиск секретов в коммитах: API-ключей, паролей баз данных, приватных SSH-ключей, токенов. Даже если секрет удалён из текущей версии файла, он остаётся в git-истории навсегда — пока не выполнен force push с перезаписью, что в корпоративных репозиториях случается редко.

Тут прямое пересечение с MITRE ATT&CK: Valid Accounts (T1078) — найденные учётные данные используются для первоначального доступа. Утёкший из git-истории AWS-ключ может дать атакующему доступ к облачной инфраструктуре (T1078.004, Cloud Accounts) быстрее, чем любой эксплойт.

git log -S, trufflehog и gitleaks для анализа git истории

Pickaxe-поиск (git log -S) — встроенный в git способ найти коммит, где определённая строка появилась или исчезла. -S подсчитывает количество вхождений строки и находит коммиты, где это число изменилось. Для regex-паттернов есть -G — он ищет коммиты, где изменённые строки содержат совпадение.

# Точный поиск: строка добавлена или удалена
git log -S "AWS_SECRET_ACCESS_KEY" --oneline -p
# Ограничение по типу файлов (Python и YAML)
git log -S "password" --oneline -- "*.py" "*.yml"
# Regex-поиск: любой Bearer-токен
git log -G "Bearer\s+[A-Za-z0-9\-_]+" --oneline

Флаг -p покажет diff — вы увидите не только коммит, но и точную строку с секретом. Для точных строк (конкретный ключ) — -S. Для паттернов (любой JWT, любой приватный ключ) — -G.

Pickaxe не масштабируется на сотни репозиториев. Для массового поиска секретов в git есть специализированные инструменты — trufflehog и gitleaks. Оба сканируют всю git-историю, включая удалённые ветки, на предмет паттернов: ключей AWS, GCP, Azure, токенов GitHub, Slack, приватных ключей SSH/PGP. Эти инструменты встраиваются в CI/CD-пайплайн как pre-commit хуки (скрипты, которые запускаются автоматически перед каждым коммитом) или отдельные стадии сборки — чтобы секрет не попал в репозиторий даже на секунду.

На собеседовании AppSec-инженера вопрос «как ты организуешь поиск утечек» подразумевает знание и ручного подхода (git log -S), и автоматизированного (trufflehog/gitleaks). Кандидат, который знает только один из них, закрывает половину задачи.

Практика перед собеседованием: делай раз, делай два, делай три

Предпосылки: установленный git (любая ОС), терминал, доступ к любому публичному репозиторию с историей более 50 коммитов.

Делай раз — blame с полным набором флагов. Склонируйте open-source проект (например, любой из OWASP-проектов). Найдите файл с бизнес-логикой. Выполните git blame -w -M -C -L 1,30 <файл>. Научитесь читать вывод: хеш, автор, дата, строка. Возьмите хеш любого коммита и выполните git show <hash>. Ожидаемый результат: за 30 секунд вы восстанавливаете историю любой строки и понимаете, зачем она была добавлена.

Делай два — bisect на искусственном баге. Создайте учебный репозиторий с 10-15 коммитами. В одном из средних намеренно «сломайте» что-то — удалите проверку входных данных, добавьте eval(). Пройдите bisect вручную: start → bad → good → проверка → repeat → reset. Затем повторите с git bisect run и простым тестом (скрипт, который проверяет наличие строки и возвращает 0/1). Ожидаемый результат: вы понимаете механику бинарного поиска и можете объяснить, когда bisect эффективнее blame.

Делай три — pickaxe-поиск секрета. В учебном репозитории добавьте в одном коммите строку API_KEY=sk-test-12345, а в следующем — удалите. Выполните git log -S "API_KEY" --oneline -p. Убедитесь, что git нашёл оба коммита — добавление и удаление. Ожидаемый результат: вы видите, что удалённый секрет остаётся в истории, и понимаете, почему это проблема.

Бонус — hot spots. Команда git log --pretty=format: --name-only | sort | uniq -c | sort -rn | head -20 показывает файлы, которые менялись чаще всего. В security-контексте это файлы с наибольшим риском: больше изменений — больше шансов на ошибку. Подход описан в книге «Code as a Crime Scene» (Adam Tornhill) и реализован в Jenkins Git Forensics Plugin, который визуализирует code churn и авторов изменений прямо в CI. Упоминание этой метрики на собеседовании показывает, что вы мыслите как аналитик, а не просто знаете команды.

Типичные вопросы на собеседовании security engineer по git и что за ними стоит:

Вопрос интервьюера Чего ждёт Плохой ответ
«Как найти, кто добавил уязвимую строку?» git blame -w -M -C, .git-blame-ignore-revs «Посмотрю git log»
«Сломался security-тест, 500 коммитов назад работал» git bisect + автоматизация через run «Проверю последние PR»
«Разработчик закоммитил секрет и удалил. Проблема решена?» Нет. Секрет в истории. Ротация + trufflehog «Да, он же удалил»
«Как организовать поиск секретов?» Pickaxe точечно, gitleaks/trufflehog массово, pre-commit превентивно «grep по репозиторию»

Ни один из этих вопросов не касается branching-стратегии. GitHub Flow — вопрос для разработчиков. Git forensics для безопасности — вопрос для AppSec.

Я провёл больше двух десятков собеседований на позиции AppSec и security engineer. Паттерн один и тот же: кандидаты приходят с отличным знанием OWASP Top 10 (перечислить категории может каждый второй), но буксуют на вопросе «покажи, как расследуешь». git blame и bisect — не «знание git». Это демонстрация расследовательского мышления. Кандидат, который за минуту через bisect находит коммит с регрессией, убедительнее того, кто 20 минут рассказывает теорию про injection.

Большинство реальных задач AppSec начинаются не с эксплойта, а с вопроса «кто и когда это изменил?». Утёкший секрет, отключённая валидация, убранный заголовок безопасности — всё расследуется через git-историю. Jenkins Git Forensics Plugin уже встраивает code archaeology прямо в CI-пайплайн — git forensics перестаёт быть бонусным навыком и становится базовым требованием. Не заучивайте команды — отработайте три сценария на реальном репозитории: blame на уязвимую строку, bisect на регрессию, pickaxe на секрет. Если ищешь первую роль в ИБ и нужна структура — на WAPT эту связку «git forensics + расследование» проходят с лабами, а на HackerLab можно погонять pickaxe-поиск на учебном репозитории.

Эту тему и смежные навыки разбирают на практике в курсе «Git. Система контроля версий» Codeby Academy.