awesome-everything EN
↑ Обратно к восхождению

Безопасность

Управление секретами: почему ключ в git — это уже взлом

Суть Учётные данные в коде — это утёкший секрет. История git хранит его после удаления, сканеры находят публичные ключи примерно за минуту, и единственный реальный фикс — ротация, а не удаление. Лестница зрелости идёт от захардкоженных ключей к управляемому короткоживущему секрету.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на junior-высоте — поверхность
◷ 16 min

Джун пушит быстрый фикс в публичный репозиторий. В диффе спрятан AWS-ключ доступа, который был «просто для теста». За минуту его уже забрал автоматический сканер, следящий за публичным потоком событий GitHub; за одиннадцать минут кто-то поднимает флот GPU-инстансов для майнинга на счёте компании. Разработчик паникует и форс-пушит коммит, удаляющий строку. Ключ всё ещё работает — он по-прежнему живёт в истории git, и ротация, а не удаление, — единственное, что останавливает взлом.

Захардкоженные учётные данные — это утёкшие учётные данные

Инстинкт — относиться к ключу в коде как к неряшливости, которую надо прибрать перед демо. Это не неряшливость, это экспозиция. В тот момент, когда учётные данные попадают в репозиторий, они есть у всех, у кого есть доступ на чтение, их несёт каждый клон, их может напечатать любой CI-лог, а если репозиторий когда-нибудь сделают публичным — они транслируются в интернет. GitHub зафиксировал более 39 миллионов утёкших секретов в 2024 году — рост на 67% за год, а GitGuardian насчитал 28,65 миллиона новых захардкоженных секретов, запушенных в публичные репозитории только за 2025 год. Это не редкая оплошность — это самый частый способ, которым реальные системы взламывают, поэтому OWASP относит управление секретами к первоклассным заботам.

Цифры по эксплуатации — та часть, что пугает людей и заставляет меняться. Исследователи, подбрасывавшие honeypot-ключи AWS, видели, как автоматические боты находят и используют их примерно за одну минуту, а security-фирмы измеряли, как сканеры забирают открытые ключи за одиннадцать минут и сразу запускают GPU-инстансы. Льготного периода нет. К моменту, когда ты замечаешь плохой коммит, атакующий уже использовал ключ.

История git — append-only, поэтому удаление — это ложь

Ловушка, в которую попадает большинство инженеров: они делают git rm файла или удаляют строку, пушат и верят, что секрета больше нет. Его есть. Модель данных git — append-only: каждый коммит сохраняется, и секрет навсегда сидит в истории каждого клона и форка. Любой, кто запустит git log -p или любой сканер, проходящий полную историю (а они все так делают), читает его так же легко, как текущий код.

Поэтому очистка состоит из двух частей, и важна по-настоящему только одна. Историю можно переписать через git filter-repo, чтобы вычистить блоб из каждого коммита, — но это не помогает тем, кто уже сделал клон, и ты никогда не уверен, что копия не утекла. Шаг, который завершает взлом, — это ротация: отзови утёкшие учётные данные у источника, чтобы значение в руках атакующего стало бесполезным. Считай скомпрометированным каждый секрет, который хоть раз касался репозитория, и ротируй его. Переписывание истории — это гигиена; ротация — это фикс.

Почему это работает

Хардкод — не единственный путь утечки. Тот же секрет может быть запечён в слой Docker-образа (любой, кто стянет образ, запускает docker history и читает его), напечатан в логи приложения или в подробную страницу ошибки, или собран в клиентский JavaScript-бандл и отгружен в каждый браузер. «Бэкендовый» секрет в Next.js-компоненте, который не server-only, — в одном неосторожном импорте от публичного бандла. Каждый из этих случаев — один и тот же провал: секрет покинул границу доверия.

Лестница зрелости: хардкод → dotenv → управляемый

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

Визуал ниже — это лестница, на которую сеньор поднимается осознанно:

СтупеньЧто даётЧто всё ещё болит
Хардкод в кодеНичего — только удобствоНавсегда в истории git; утекает на каждом клоне, в логе, при публичном пуше
.env + .gitignoreВне git, вне образа при правильной настройкеPlaintext на диске и в CI; живёт в env процесса; нет access control и аудита; один плохой .gitignore от катастрофы
Менеджер секретов (Vault, AWS Secrets Manager, SOPS)Шифрование at rest, access control, аудит-лог кто что читалОперационная цена; всё ещё долгоживущий, если хранишь только статические значения
Динамические, короткоживущие секретыУчётка на запрос с TTL, авто-отзыв, аудит по каждому сервисуБольше всего настройки; нужна интеграция, которую понимает приложение

Большой скачок — от .env к менеджеру секретов. Файл .env действительно лучше хардкода — он держит значение вне коммита — но это всё равно plaintext, лежащий на ноутбуке каждого разработчика и на CI-раннере, читаемый любым, у кого есть доступ к машине, и невидимый для любого аудита. Менеджер вроде HashiCorp Vault, AWS Secrets Manager или SOPS добавляет три вещи, которые .env дать не может: шифрование at rest, access control (этот сервис может читать этот секрет и никакой другой) и аудит-след каждого чтения. Когда случается инцидент, именно аудит-лог говорит, чью учётку ротировать и чего она касалась.

Короткоживущий бьёт долгоживущий: TTL — это радиус взрыва

Верхняя ступень — то, к чему целятся сеньорские команды, и она меняет математику утечки. Статические долгоживущие учётные данные — самый частый вектор атаки именно потому, что они валидны, пока человек не вспомнит ротировать их, — что после утечки часто никогда. Динамический секрет генерируется по запросу со встроенным TTL и автоматически отзывается по истечении. Движок баз данных Vault, например, выпускает уникального пользователя БД на запрос с TTL в один час на проде; утёкшая учётка мертва за шестьдесят минут — заметил это кто-то или нет.

Из этого следуют ещё два свойства. Поскольку каждый потребитель получает уникальную учётку, аудит-лог может назвать точный экземпляр сервиса, который что-то сделал, — ты не пялишься на один общий username, используемый всем подряд. И динамические учётки делают least privilege применимым: каждый lease ограничен ровно теми правами, что нужны роли, поэтому украденный ключ read-only сервиса отчётов не может удалить продовую базу. Сеньорский трейдофф реален — динамические секреты дороже всего в настройке и требуют, чтобы приложение получало и продлевало lease, — но для всего, что защищает продовые данные, радиус взрыва в один час бьёт бесконечный.

Выбери лучший вариант

Бэкенд-сервису нужны учётные данные БД на проде. У команды есть спринт на это. Выбери подход, который защитит сеньор.

Викторина

Ты обнаружил, что API-ключ закоммитили в репозиторий месяц назад. Удаляешь строку и форс-пушишь. Секрет теперь в безопасности?

Викторина

Почему динамическая короткоживущая учётка БД бьёт долгоживущую для прода?

Расставь шаги по порядку

Ты только что нашёл живой облачный ключ, закоммиченный в публичный репозиторий. Расставь реакцию от первого к последнему:

  1. 1 Ротируй учётку сейчас — отзови утёкший ключ у источника, чтобы он перестал работать
  2. 2 Проверь аудит/биллинг-логи провайдера на то, что ключ уже сделал
  3. 3 Перепиши историю git (git filter-repo), чтобы вычистить блоб из каждого коммита
  4. 4 Добавь pre-commit сканер секретов (gitleaks/trufflehog), чтобы это не повторилось
  5. 5 Перенеси секрет в менеджер с access control и короткоживущими lease
Вспомните перед уходом
  1. 01
    Коллега закоммитил пароль БД, потом удалил строку и запушил. Объясни, почему это не решает проблему и какая реальная ремедиация.
  2. 02
    Проведи коллегу вверх по лестнице зрелости секретов и объясни, почему каждая ступень лучше, закончив тем, почему короткоживущие динамические секреты — цель.
Итог

Учётные данные в исходном коде — это не вопрос аккуратности, а утёкший секрет, и утёкшие ключи на публичных репозиториях используют примерно за минуту автоматические сканеры, которые тут же поднимают ресурсы на твоём счёте. Определяющая ловушка в том, что история git — append-only: удаление строки или даже форс-пуш не убирает секрет из прошлых коммитов или из чьего-то клона, поэтому единственное, что завершает экспозицию, — это ротация, отзыв значения у источника, подкреплённый проверкой аудит и биллинг-логов на то, что уже произошло. Дальше сеньор поднимается по лестнице зрелости: прочь от хардкода, мимо файла .env (вне git, но всё ещё plaintext, неконтролируемый и неаудируемый), в менеджер секретов, добавляющий шифрование at rest, access control и аудит-след, и наконец к динамическим короткоживущим секретам, чей TTL ограничивает радиус взрыва любой утечки, обеспечивая least privilege на каждого потребителя. Страховочная сетка под всем этим — pre-commit сканер секретов, чтобы следующая ошибка была поймана ещё до того, как покинет машину.

Продолжить восхождение ↑Управление секретами: обзор с выбором ответа
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.