Почему секреты нельзя хранить в коде
Разбираем, во что обходится привычка держать пароли и токены прямо в коде и конфигах.
Секрет — это любой чувствительный фрагмент данных (пароль, токен, ключ API, приватный ключ TLS), компрометация которого даёт злоумышленнику доступ к системе или данным.
Почти каждый проект начинается одинаково: разработчику нужно подключиться к базе данных, и он пишет строку подключения прямо в исходник. Работает — значит хорошо. Через полгода в репозитории десятки паролей, ключей платёжного шлюза и токенов облака, и никто уже не помнит, какие из них реальные, а какие тестовые. Это корень проблемы.
Чем плох хардкод
Когда секрет лежит в коде, он немедленно наследует все свойства кода: его копируют, форкают, отправляют в чат, кладут в логи сборки. Пароль перестаёт быть секретом в тот момент, когда его увидел хотя бы один лишний человек или сервис.
import psycopg2
# ТАК ДЕЛАТЬ НЕЛЬЗЯ: пароль прямо в исходнике
conn = psycopg2.connect(
host="db.internal",
user="app",
password="S3cr3t-Pr0d-Pass!", # утечёт вместе с кодом
dbname="orders",
)
print("connected")
Стоит этому файлу попасть в публичный или даже внутренний репозиторий — пароль скомпрометирован. Боты непрерывно сканируют GitHub на предмет ключей: типичное время от публикации ключа AWS до его эксплуатации измеряется минутами.
Почему .env в гите не спасает
Следующий шаг команды — вынести секреты в файл .env и добавить его в .gitignore. Это лучше, но решает лишь половину задачи.
DATABASE_URL=postgres://app:[email protected]/orders
STRIPE_KEY=sk_live_51H...
JWT_SECRET=k8s-super-secret-value
Проблемы остаются. Файл всё равно лежит на диске в открытом виде. Его копируют коллеги через мессенджер. Один неосторожный git add . — и секрет в истории навсегда. Нет ротации: пароль один и тот же годами. Нет аудита: невозможно узнать, кто и когда читал секрет. Нет разграничения: любой, у кого есть файл, видит ВСЕ секреты сразу.
Как работает под капотом утечка из git
Git хранит полную историю. Даже если вы удалили строку с паролем следующим коммитом, она остаётся в объекте предыдущего коммита и достаётся одной командой:
# любой, у кого есть клон, достанет старый секрет
git log -p -- .env
git show <старый-хеш-коммита>:.env
Поэтому правило простое: если секрет хоть раз попал в git — считайте его скомпрометированным и ротируйте, а не «удаляйте коммит».
Частые ошибки
- «У нас приватный репозиторий, всё ок» — приватность не отменяет ни утечек через подрядчиков, ни логи CI, ни случайную публикацию.
- Логирование строки подключения целиком — пароль оказывается в системе сбора логов, доступной полкоманде.
- Один пароль на все окружения — компрометация dev тянет за собой prod.
- «Удалю коммит и всё» — секрет уже в истории и, возможно, в форках; нужна ротация.
Итог
- Секрет в коде = секрет, скомпрометированный при первом же копировании, форке или логе.
.envв.gitignoreубирает случайный коммит, но не даёт ротации, аудита и разграничения доступа.- Попавший в git секрет нужно ротировать, а не пытаться «затереть» из истории.