Самая частая security-ошибка в Git - закоммитить API-ключ, пароль
БД, AWS credentials. Это считается «утечкой» сразу, как только
попало в репо: даже если ты удалил коммитом дальше, файл лежит в
истории, доступен git show <sha>:path, и кто угодно с доступом к
репо его прочитает.
Если репо публичный - секрет компрометирован за минуты: боты сканируют GitHub и автоматически пытаются использовать найденные ключи. На AWS или похожем cloud-провайдере утёкший ключ способен быстро накрутить заметные расходы (типичный сценарий - запуск тяжёлых EC2/GPU-инстансов под майнинг) ещё до того, как ты заметишь утечку.
Как защищаться: три слоя
1. Не пускать секреты в репо вовсе
.env-файлы в.gitignore(gitignore).- Secrets из env-переменных, не из файлов.
- В коде - placeholder'ы, реальные значения из vault/AWS Secrets Manager/Doppler/1Password.
2. Pre-commit hook со scanner'ом
Самые популярные инструменты:
- gitleaks - Go-бинарь, быстрый. Конфиг в
.gitleaks.toml. - detect-secrets (Yelp) - Python, более тонкая настройка через
«baseline».
- trufflehog - Go, сканит даже entropy высокую (находит случайно похожее на токены).
Через pre-commit framework (gpg-signing):
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.0
hooks:
- id: gitleaks
Теперь коммит с подозрительной строкой блокируется:
gitleaks failed: aws-access-key found in src/config.py:15
3. Серверное сканирование
- GitHub Secret Scanning - встроено для публичных репо бесплатно, для приватных через GHAS (платно). Сканирует на приёме push'а; при найденном ключе автоматически уведомляет провайдера (AWS, Stripe, etc.), и тот может отозвать ключ.
- GitLab Secret Detection - аналог в SAST-наборе.
- Самодельный pre-receive hook на bare-сервере, который отвергает push с подозрительными строками.
Серверный слой - финальный страховочный сетка. Даже если
разработчик пропустил pre-commit (--no-verify), серверный
scanner поймает.
Что делать, если утечка уже произошла
Прямой порядок действий:
1. Ротация ключа - немедленно
Не «починим историю и потом ротируем». Сначала ротация:
- AWS: создать новый access key, удалить старый.
- Stripe: revoke API key в дашборде.
- GitHub PAT: revoke в Settings.
- Любой провайдер: в течение получаса.
Это единственный способ устранить риск. Чистка истории - это чистота, но не безопасность.
2. Уведомить команду
Кто-то мог склонировать репо до фикса. Уведомить, что секрет ротирован, чтобы они не пытались использовать старый.
3. (Опционально) Чистка истории
Если репо приватный и секрет точно не у злоумышленника - можно сократить exposure через git-filter-repo:
git filter-repo --replace-text replace.txt
# где replace.txt содержит:
# AKIA********** ==> [REMOVED]
Это переписывает всю историю. После - git push --force (нужны
права + branch protection временно отключить). Все клоны устаревают,
всех просят сделать git clone заново.
Не делай чистку без ротации - это создаёт ложное чувство безопасности. Ротация - обязательна, чистка - опциональна.
Что чаще всего утекает
- AWS access keys (AKIA*) - самые распространённые и опасные.
- GitHub PAT/Personal Access Tokens (ghp_*).
- Stripe/Twilio/SendGrid API ключи.
- Пароли БД в
database.yml,application.properties. - OAuth client_secret в
.env-файлах. - SSH-ключи в
.ssh/-копии (см. ssh-keys-git). - Сертификаты и приватные ключи в
.pem,.key,.crt.
Большинство этих паттернов scanner'ы знают сходу - gitleaks поставляется с правилами на сотни провайдеров.
Подводные камни
- False positives. Scanner может посчитать random'ный hash
«утекшим ключом». Для detect-secrets есть
--baseline, который помнит «эти известные, не алертить». - Старые секреты в истории. После активации scanner'а на CI он начнёт алертить на старую историю. Стратегия - отдельно почистить старые (или принять как baseline) и потом включить scanner на новые.
.env.exampleтоже сканируется. Если в нём вместо placeholder'а реальное значение - scanner поймает. Это норма, держи placeholder'ы (<your-key-here>).