Сможет ли интерактивная перебазировка git, удаляющая коммит, действительно убрать разоблачение ключей / секретов / паролей API? - PullRequest
0 голосов
/ 29 мая 2019

Важно НЕ хранить пароли и секреты в репозиториях кода.

Иногда мы жестко программируем пароль API во время разработки приложения.Мы удаляем его, часто превращая его в переменную окружения, которую мы установили с помощью export (Unix).Очевидно, что лучшей практикой было бы использование переменных окружения с самого начала.

Но что происходит в случае, когда мы не настолько осторожны, и мы ОБЯЗАНЫ с тем, чтобы изменение, при котором пароль был открыт.
Первый шаг -чтобы быстро удалить их, зафиксировать и отправить это изменение.
OK

Но ...

Пароль все еще находится в истории git, так что любой, кто имеет доступ к репозиторию git, может получитьpw.Не хорошо.

Но ...

Затем мы делаем интерактивную перебазировку git и удаляем (не сквош) коммит-нарушитель = тот, чей пароль добавлен в историю.

Устранит ли это проблему и позволит ли пароль больше не быть доступным в любом случае в git?

Как это повлияет на код, когда я получу этот коммит,Если есть другой код, кроме строки (ов) с паролем (ями), вероятно, мне нужно будет повторить те изменения, которые будут потеряны.Если коммит произошел много лет назад, я мог бы представить проблемы, если какой-либо коммит с тех пор также изменил ту же строку.Надеюсь, что нет.

1 Ответ

1 голос
/ 30 мая 2019

Существует множество ответов о как удалить конфиденциальные коммиты, например, Удалить конфиденциальные файлы и их коммиты из истории Git . Любой хороший ответ предупреждает вас, что в любом случае, вероятно, уже слишком поздно, и это правда. Не так много подробностей о , когда и почему слишком поздно, но ответ довольно прост: не так уж много использования . Остальная часть этого ответа о том, когда и почему слишком поздно, и почему просто удалить коммит с интерактивной перебазировкой недостаточно.

Суть проблемы в том, что коммиты не могут быть изменены, и Git готов добавить new коммитов. Удаление старых / мертвых коммитов (и других мертвых объектов) происходит как побочный эффект, с небольшим контролем с вашей стороны. Когда вы делаете что-либо практически - независимо от того, что: git commit --amend, git rebase -i, git reset --hard, ничего из этого не имеет значения - любой существующий коммит остается в вашей базе данных коммитов, неизменным, невозмущенным и все еще доступным по хэш-идентификатору. Тем не менее, можно реально удалить коммит. Просто сложно сделать это контролируемым и правильным образом.

Представление и нахождение коммитов

Каждый коммит - фактически, каждый объект 1 в основной базе данных Git - доступен по его хэш-идентификатору. Идентификатор хэша last commit в ветви находится во второй, меньшей базе данных. По сути, имя ветви, такое как master, говорит: коммит-коммит master равен a123456..., который предоставляет хэш-идентификатор объекта фиксации, чтобы вы - или Git - могли вернуться к Основная база данных и сказать: Получить мне объект a123456....

Каждый коммит может перечислять хеш-код (ы) некоторых предыдущих или родительских коммитов. То есть, получив объект a123456..., вы можете ловить рыбу внутри него для родительских хеш-идентификаторов. Если (один) родительский хэш-идентификатор a123456... равен 9876543..., вы возвращаетесь в основную базу данных и говорите: * Get me object 9876543..., и у вас есть предыдущий коммит. Вот как вы - и Git - можете начинать с конца ветви и работать в обратном направлении, по одному коммиту за раз:

... <-grandparent <-parent <-last-commit   <--branchname

Если мы используем одиночные заглавные буквы для обозначения хеш-идентификаторов и просто помним , что стрелки (от дочернего к родительскому) всегда указывают назад, мы получим нечто, что будет легче нарисовать, когда у вас несколько ветвей :

...--E--F--G   <-- master
         \
          H  <-- develop

Но во всех случаях, когда вы делаете что-то, чтобы «изменить» свою историю - например, если мы решим, что фиксация G плохая и ее необходимо заменить - вы на самом деле ничего не измените . Вместо этого Git по сути просто удаляет плохой коммит с пути:

          G
         /
...--E--F--I   <-- master
         \
          H  <-- develop

Основная база данных объектов не очищена немедленно, и если у вас есть любой способ запомнить хэш-идентификатор commit G, вы можете попросить Git о G по этому хэш-идентификатору. Git представит его вам, потому что находится в базе данных!

Это то же самое описание верно, независимо от того, как вы «удаляете» или «меняете» коммит: Git просто делает копии каждого другого коммита, так что «удаленный» или «измененный» коммит (здесь G должно быть удалено) теперь находится на другой ветке:

...--o--F--G--H--J--...   <-- branch

становится:

          G--H--J--...   [previous branch, now abandoned]
         /
...--o--F--H'-J'-...   <-- branch

, где H' - это копия H, настроенная на добавление после F вместо G, J' - копия J, адаптированная на поставку после H', и так далее. Опять же, G на самом деле не ушло , оно просто сброшено с пути вместе со всеми его потомками. Все его потомки заменены слегка измененными копиями с новыми разными хэш-идентификаторами.


1 Существует четыре типа объектов. Commit , tree и blob объекты работают вместе для хранения файлов в коммитах, с аннотированным тегом объектов четвертого типа. Каждый коммит относится к одному дереву; это дерево ссылается на дополнительные поддеревья, если необходимо, и на BLOB-объекты для хранения файлов, которые сопровождают этот коммит.


Удаление коммц

Итак, когда - и как и почему - коммиты в конечном итоге исчезают? Ответ заключается в том, что Git имеет команду обслуживания git gc, задача которой состоит в том, чтобы обходить всю основную базу данных каждого объекта, а также обходить другую базу данных всех имен, по которой можно найти объекты. Если есть имя no , по которому мы можем найти commit G, после операции, подобной описанной выше, git gc определит, что это так, и - в конечном итоге - выкинет G из Основная база данных, использующая любые обычные функции удаления операционной системы для удаления файла. 2

Более формально, чтобы git gc удалить объект из основной базы данных, объект должен быть недоступен . Для подробного обсуждения понятия достижимости см. Think Like (a) Git . К сожалению, для вашего конкретного случая использования набор имен, по которым мы можем достичь коммитов, включает в себя любой коммит в любом reflog .


2 Как правило, это небезопасное удаление, так что если у вас есть контроль над базовым носителем, вы все равно можете получить данные обратно таким образом, но теперь очевидно, что гораздо труднее. В любом случае, теперь никто не может просто попросить Git-репозиторий для коммита G по хеш-идентификатору. Остерегайтесь файловых систем, которые поддерживают моментальные снимки, однако: вы можете просто вернуться к предыдущему снимку и восстановить весь репозиторий, каким он был на момент моментального снимка!


Поиск коммитов часть 2: reflogs

Существует рефлог для каждого имени ветви, например master, плюс один для HEAD. (Возможно, есть дополнительные reflogs, но здесь есть два важных.) В приведенном выше примере commit G больше не доступен с именем master, но есть еще две записи reflog, master@{1} и HEAD@{1}, оба сервера для поиска коммита G. Так что git gc не удалит коммит G - пока нет.

Записи reflog, которые найдут G , будут удалены, в конце концов. В частности, git reflog expire автоматически удаляет достаточно старые и, следовательно, expired reflog записей. Сколько лет вам достаточно - это то, что вы можете настроить, но по умолчанию оно составляет 30 или 90 дней, 3 , а в данном случае - 30 дней.

Что означает , так это то, что по умолчанию G будет оставаться до тех пор, пока git gc не использует git reflog для удаления записей reflog, как только они станут достаточно старыми, т. Е. Не менее 30 дней с этого момента. Вы можете использовать git reflog (см. документацию ), чтобы быстрее удалить или истечь записи для G, если вы хотите ускорить эту часть; или см. клонирование ниже.

Как только записи reflog исчезнут, так что G действительно (глобально) недоступен, git gc удалит его. Вы можете сказать, что это произошло, потому что git show <em>hash</em> и git rev-parse <em>hash</em> скажут вам, что они понятия не имеют, о каком хэш-идентификаторе вы говорите.

Помните также, что если ваш Git связался с другим Git, ваш Git мог дать этому другому Git коммит G. В частности, когда вы запускаете git push, ваш Git вызывает другой Git и передает их коммитам. Если вы дали их коммит G, то ничто из того, что вы делаете в своем собственном хранилище, не сможет вернуть это. Если вы разрешите другим пользователям git fetch из вашего хранилища, они, возможно, взяли копию G, и опять же, ничто из того, что вы делаете в своем собственном хранилище, не может забрать это обратно: вы должны убедить их в отменить коммит.

ReflogФайлы git clone не копируются, поэтому другой способ избавиться от G без ожидания - клонировать свой собственный репозиторий. git clone создает новый репозиторий, а затем извлекает его из исходного репозитория. Коммиты, которые получает выборка, - это те, которые доступны из имен, которые предоставляет исходный репозиторий. Таким образом, вместо ручного истечения срока действия некоторых записей reflog и последующего запуска git gc, вы можете просто клонировать свой собственный репозиторий. Здесь есть один недостаток: вы теряете сеть безопасности всех своих повторных журналов, и ваши собственные имена ветвей становятся именами origin/* вашего нового хранилища. 4


3 Выбор между 30 и 90 днями здесь зависит от того, достижимо ли значение в reflog из фиксации, на которую указывает сама ссылка. В этом случае имя master указывает, например, на фиксацию I, и невозможно вернуться назад от I к G, поэтому значение в master@{1}, которое указывает на G, недоступно из значения master. Это означает, что срок действия gc.reflogExpireUnreachable - тот, который по умолчанию равен 30 дням, а не gc.reflogExpire, который по умолчанию равен 90 дням.

Обратите внимание, что мы опять зависим от концепции достижимости через ориентированный граф. Это один из ключей к пониманию Git.

4 Вы можете использовать git clone --mirror, но вы получите bare хранилище и хранилище с неподходящим значением по умолчанию fetch. Затем вы можете исправить эти два, но если вы знаете, как все это сделать, вы все равно, вероятно, захотите использовать что-то отличное от --mirror. ?


Резюме

Если:

  • вы не поделились нежелательными коммитами ни с кем (без извлечений или толчка), и
  • Вы удаляете все ссылки на коммиты или ждете 30 дней, а затем запускаете git gc

затем фиксация действительно исчезнет, ​​если не произойдет никакого воскрешения через моментальные снимки уровня файловой системы. Вы можете передать хеш-код на git show или git rev-parse, чтобы убедиться, что он пропал. Но если фиксация могла быть скопирована где-либо еще, вы больше не можете это контролировать.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...