
Почему GitHub Commits не так частные, как вы думаете
1 августа 2025 г.У разработчиков есть общее заблуждение, которое, как только вы удалите коммит, он ушел навсегда. Вы можете заставать переписать историю или удалить ветвь, которая имела конфиденциальную информацию, и предположить, что она безопасно стерта. Но GitHub и GIT сами не работают.
На самом деле, GitHub может сохранить и выявлять «удаленные» коммиты таким образом, что не очевидно. При определенных условиях коммиты, по вашему мнению, были удалены, можно до сих пор доступно публично. Это создает иллюзию конфиденциальности - разработчики чувствуют себя в безопасности, но на самом деле следы конфиденциальной информации могут оставаться доступными.
В этой статье я буду проходить через то, как это происходит, демонстрируют случаи, когда удаленные или частные коммиты все еще можно получить, и объяснить, что это значит для команд, занимающихся безопасностью, носителей с открытым исходным кодом и разработчиков, которые неверно применяют гигиену GitHub.
Как GIT обрабатывает "удаленные" коммиты
Gitэто система управления распределенной версией, которая отслеживает версии файлов. Это означает, что разработчики могут иметь свою собственную версию филиалов независимо.
По своей сути, GIT является базой данных, подлежащей обработке контента. Коммитами, деревья и капли хранятся на основе их хэша SHA-1 или SHA-256. GIT на самом деле не «удаляет» вещи - это просто выдает их.
Давайте посмотрим на то, как это выглядит на практике:
Сначала инициализируйте новый репозиторий GIT и добавьте файл readme.md
$ git init
Initialized empty Git repository in /Users/vshelkovnikov/GitHub/demo/.git/
$ touch Readme.md
$ git add .
$ git commit -m "First commit"
[main (root-commit) fe8b8e6] First commit
1 file changed, 1 insertion(+)
create mode 100644 Readme.md
Добавьте некоторые изменения в readme.md и снова совершите.
$ git add .
$ git commit -m "Second commit"
[main 2b9714e] Second commit
1 file changed, 1 insertion(+), 1 deletion(-)
На данный момент у нас есть два коммита. Вы можете проверить их с помощьюgit log
:
$ git log
commit 2b9714ec5b229700eed2ce2dc673b8d8b52a1f35 (HEAD -> main)
Author: C4tWithShell <vladimir.shelkovnikov@aiso.team>
Date: Mon Jul 28 17:33:26 2025 +0300
Second commit
commit fe8b8e6d36d640a29dc893ecc81bc1a2eeead1ed
Author: C4tWithShell <vladimir.shelkovnikov@aiso.team>
Date: Mon Jul 28 17:32:33 2025 +0300
First commit
HEAD
указатель, расположенный в.git/HEAD
файл в вашем хранилище. Этот файл обычно содержит ссылку на текущую ветвь (например,,ref: refs/heads/main
) или конкретный хэш коммита, если вы находитесь в отделении головы.
Давайте сбросим первого коммита с использованиемgit reset HEAD^ --hard
Полем
$ git reset HEAD^ --hard
HEAD is now at fe8b8e6 First commit
Мы видим этоHEAD
переключился на первый коммит:
$ git log
commit fe8b8e6d36d640a29dc893ecc81bc1a2eeead1ed (HEAD -> main)
Author: C4tWithShell <vladimir.shelkovnikov@aiso.team>
Date: Mon Jul 28 17:32:33 2025 +0300
First commit
Второй коммит исчез. Это похоже на то, что происходит, когда вы принуждаете (git push -f
) Это может появитьсячто код был стерт - но на самом деле вы все равно можете восстановить его, используяgit reflog
Полем
$ git reflog
fe8b8e6 (HEAD -> main) HEAD@{0}: reset: moving to HEAD^
2b9714e HEAD@{1}: commit: Second commit
fe8b8e6 (HEAD -> main) HEAD@{2}: commit (initial): First commit
Здесь мы видим, что второй коммит имеет хэш SHA-12b9714e
Полем
Давайте восстановим его, сбросивHEAD
Вернемся к нему.
$ git reset 2b9714e
Unstaged changes after reset:
M Readme.md
$ git log
commit 2b9714ec5b229700eed2ce2dc673b8d8b52a1f35 (HEAD -> main)
Author: C4tWithShell <vladimir.shelkovnikov@aiso.team>
Date: Mon Jul 28 17:33:26 2025 +0300
Second commit
commit fe8b8e6d36d640a29dc893ecc81bc1a2eeead1ed
Author: C4tWithShell <vladimir.shelkovnikov@aiso.team>
Date: Mon Jul 28 17:32:33 2025 +0300
First commit
Давайте посмотрим на хэши коммита. Git поддерживает обаполныйисокращенВерсии хэша:
Полный хэш | Короткая версия |
FE8B8E6D36D640A29DC893ECC81BC1A2EEAD1ED | F38b8e6 |
2B9714EC5B229700ED2CE2DC673B8D8B52A1F35 | 2B9714E |
Каждый коммит в GIT имеет уникальный хэш, который действует как его «удостоверение личности». Хэш рассчитывается на основе всегоCompe Content, включая:
- Структура файла и каталога (объект «дерево»)
- Сообщение о коммите
- Метаданные, такие как автор, комитет и временные метки
- Хэш родительского коммита (и)
GIT использует SHA-1 по умолчанию (или, необязательно SHA-256 в качестве экспериментальной функции). Обычно вам не нужен полный хэш - GIT позволяет использовать короткую версию (обычно достаточно 4–7 символов). В моем примере,f38b
и2b97
Вот как работает GIT.
Но как насчет GitHub? Вот где все становится интересным.
А как насчет GitHub?
GitHubявляется распределенной платформой, построенной на вершине GIT, не только наследует децентрализованную механику GIT, но и вводит свои собственные слои сложности и рисков.
Давайте вернемся к эксперименту с ранее.
Я создал публичный хранилище и добавил два коммита:
Тогда я побежал:
git reset 10a47932 # (initial commit)
git push -f
Что мы видим на GitHub?
Второй коммит исчез из истории.
Конечно, я могу восстановить его, используя локальный инструмент GIT (как показано ранее), но можем ли мы по -прежнему получить к нему доступ к самому GitHub?
Да!
Вы можете получить доступ к коммитированию непосредственно в вашем браузере, используя:
https://github.com/<user>/<repo>/commit/<hash>
Для моего примера,https://github.com/c4twithshell/demo/commit/cbc61bd83a87561c101a325b03ec9873a7c0cc62
GitHub предупреждает:
«Этот коммит не принадлежит ни к какой ветви в этом хранилище и может принадлежать вилке за пределами репозитория».
НоВесь контент коммита все еще доступен.
Общественные репозитории
Поскольку GitHub является распределенной платформой, мы можем распространить эту идею на подключенные репозитории- восходящие и их вилки.
Могу ли я получить доступ к Commits из удаленной вилки?
Я разделил свой демонстрационный репозиторий, работал над ним и добавил новый.md
Файл по ошибке.
Затем осознал мою ошибку и удалил черезgit push -f
Полем
Я больше не вижу этого коммита, ноэто действительно ушло?
Благодаря хэшам SHA-1 мы можем найти коммиты, используя всего 4–7 шестнадцатеричных символов. Имея только 65 536 (16⁴) возможных комбинаций, представленные грубые префиксы SHA, разбитые грубые, являются тривиальными для современных машин и полностью автоматизируют.
Я все еще могу найти этот коммит в своей вилке. Я также могу получить к нему доступ кОригинальный репозиторий, даже если вилка была позже удалена.
Что, если восходящее репо удалено?
Хорошо, давайте перевернем.
Предположим, что я заканчиваю секретОригинальный репо, затем удалите его непосредственно перед тем, как кто -либо разбивает его. Я в безопасности?
На этот раз давайте даже удалим мой репозиторий вверх по течению, чтобы быть уверенным.
После удаления моего демонстрационного репозитория я вижу, что больше нет "разветвленной" ссылки, и я не вижуSECRET.md
файл.
На этот раз я создаювилка этой вилкии копайте историю коммита, используя короткий SHA. Это означает, что я все еще могу восстановитьSECRET.md
совершить!
Потому что, покаОдна вилка остается, коммит существует.
Как это возможно?
Это возможно из -за сети хранилища в GitHub -Сеть отношений между репозиторием и его вилкамиПолем Вы можете исследовать это по адресу:
https://github.com/<user>/<repo>/network
Это показывает:
- Кто развел репо;
- Как Commits расходились через вилки;
- Коммиты, которые существуют в вилках, нонетВ основном репозитории.
Поэтому, когда кто-то разжигает репо, GitHub отслеживает отношения между родителями и ребенком. Даже удаленные или сделанные вилки-предприниматели все еще могут отслеживать в сетевом графике, если:
- Вилка когда -то была публичной;
- Коммуты были выдвинуты до того, как вилка была удалена/частной.
Магазины GitHub совершают хэши, которые могут оставаться доступными, если вы знаете SHA, который является известным вектором утечки метаданных.
Это влияет на частные репо?
Давайте попробуем сЧастный репозиторийПолем
Я создаю личный репо и распахнул его. Вилка остается частной сНет возможности сделать это публичнымПолем Я добавил дополнительный файл в вилку
Несмотря на это, я могу получить доступ к этому коммитию отОригинальный репоИспользуя свой короткий SHA.
По крайней мере, в этом случае,видимость контролируется- Вилка не может быть обнародована, и доступ ограничен соавтором.
Но вот настоящая проблема ...
Я видел компании с открытым исходным кодом их внутренних репо. Прежде чем сделать это, они часто тщательно чистят основной репо.
Но как насчет вилок?
Когда частное репо обнаружено:
- АОригинальная сеть вилок репостановится замороженным в момент публикации.
- Всекоммиты, сделанные перед публикациейв частных вилках могут статьпублично видимоПолем
- GitHubне предупреждаетВы об этом.
Таким образом, даже если ваше основное репо является чистым, вы можете разоблачить секреты отПредыдущие частные вилкиПолем
Давайте проверим. Я изменил видимость моего первоначального репо. У него есть только один чистый коммит и только один файл.
Могу ли я получить доступ к коммитию в своей частной вилке?
Успех! Мы можем увидеть все коммиты, сделанные в частной вилке до того момента, как был опубликован оригинальный репозиторий. Чтобы проверить, давайте добавим новый коммит в нашу личную вилку:
Теперь давайте попробуем получить доступ к нему из общественного хранилища:
Почему это так? Потому что, как только репо станет публичным, GitHubразделяет сети репозиторийПолем Commits, добавленные позже в частную вилку, становятся изолированными.
Такое поведение применяется в обоих направлениях:
- Коммитами в частных вилках после публикации невидимы от публичного репо.
- Коммитами в общественном репо после этого момента невидимы от частной вилки.
Это ошибка?
Нет, это разработанное поведение GitHub, и они даже упоминают об этом в своей документации. К сожалению, не так много людей копаются в этом.
Прочитайте ниже - Github на вилках видимости:
Что можно сделать, чтобы исправить это?
1. Обратитесь GitHub как к публичному - всегда
Предположим, что все, что вы нажимаете, может быть выставлено в конечном итоге. СекретыНе принадлежите к gitПолем Используйте менеджер «Секреты» - Vault, Manager Secrets, Doppler, Secrets GitHub и т. Д.
2. Очиститесь правильно перед публикацией
Используйте такие инструменты, как:
- Трюфельхог
- глубокий секрет
- Секреты Semgrep
- BFG Repo-Cleaner
- git filter-repo
Я рекомендую:
deepsecrets
илиsemgrep-secrets
в сочетании сtruffleHog
илиgitleaks
Полем Они обнаруживают секретына основе контекста, не просто энтропия или регуляция. например.,passwd: hello
могут быть пропущены стандартными инструментами, но не глубокими режимами. Но вы должны ожидать ложных срабатываний, так как это можно упомянуть в качестве примеров;- Автоматизируйте сканирование в трубопроводах CI.
3. Свяжитесь с поддержкой GitHub для удаления
Если вы случайно выдвинули конфиденциальные данные, GitHub может очищать объекты из своего бэкэнда, если вы связываетесь с поддержкой, но это не является мгновенным или гарантированным.
4. Поверните секреты, если они подвергаются воздействию
Как самый важный шаг, поверните секреты вместо того, чтобы пытаться их удалить. После того, как секрет будет выставлен, предположим, что он скомпрометирован и измените его. Не рискуйте
Оригинал