git推送密码_保护代码完整性(六):在 Git 上使用 PGP
在本系列教程中,我們提供了一個使用 PGP 的實用指南,包括基本概念和工具、生成和保護你的密鑰。如果你錯過了前面的文章,你可以查看下面的鏈接。在這篇文章中,我們談一談在 Git 中如何集成 PGP、使用簽名的標簽,然后介紹簽名提交,最后添加簽名推送的支持。
- 第一部分:基本概念和工具
- 第二部分:生成你的主密鑰
- 第三部分:生成 PGP 子密鑰
- 第四部分:將主密鑰移到離線存儲中
- 第五部分:將子密鑰移到硬件設備中
Git 的核心特性之一就是它的去中心化本質 —— 一旦倉庫克隆到你的本地系統,你就擁有了項目的完整歷史,包括所有的標簽、提交和分支。然而由于存在著成百上千的克隆倉庫,如何才能驗證你下載的倉庫沒有被惡意的第三方做過篡改?你可以從 GitHub 或一些貌似官方的位置來克隆它們,但是如果有些人故意欺騙了你怎么辦?
或者在你參與的一些項目上發現了后門,而 “Author” 行顯示是你干的,然而你很確定 不是你干的,會發生什么情況?
為解決上述問題,Git 添加了 PGP 集成。簽名的標簽通過確認它的內容與創建這個標簽的開發者的工作站上的內容完全一致來證明倉庫的完整性,而簽名的提交幾乎是不可能在不訪問你的 PGP 密鑰的情況下能夠假冒你。
清單
- 了解簽名的標簽、提交和推送(必要)
- 配置 git 使用你的密鑰(必要)
- 學習標簽如何簽名和驗證(必要)
- 配置 git 總是簽名帶注釋標簽(推薦)
- 學習提交如何簽名和驗證工作(必要)
- 配置 git 總是簽名提交(推薦)
- 配置 gpg-agent 選項(必要)
考慮事項
git 實現了 PGP 的多級集成,首先從簽名標簽開始,接著介紹簽名提交,最后添加簽名推送的支持。
了解 Git 哈希
git 是一個復雜的東西,為了你能夠更好地掌握它如何集成 PGP,你需要了解什么是”哈希“。我們將它歸納為兩種類型的哈希:樹哈希和提交哈希。
樹哈希
每次你向倉庫提交一個變更,對于倉庫中的每個子目錄,git 都會記錄它里面所有對象的校驗和哈希 —— 內容(blobs)、目錄(trees)、文件名和許可等等。它只對每次提交中發生變更的樹和內容做此操作,這樣在只變更樹的一小部分時就不必去重新計算整個樹的校驗和。
然后再計算和存儲處于頂級的樹的校驗和,這樣如果倉庫的任何一部分發生變化,校驗和將不可避免地發生變化。
提交哈希
一旦創建了樹哈希,git 將計算提交哈希,它將包含有關倉庫和變更的下列信息:
- 樹哈希的校驗和
- 變更前樹哈希的校驗和(父級)
- 有關作者的信息(名字、email、創作時間)
- 有關提交者的信息(名字、email、提交時間)
- 提交信息
哈希函數
在寫這篇文章時,雖然研究一種更強大的、抗碰撞的算法的工作正在進行,但 git 仍然使用的是 SHA1 哈希機制去計算校驗和。注意,git 已經包含了碰撞防范程序,因此認為對 git 成功進行碰撞攻擊仍然是不可行的。
帶注釋標簽和標簽簽名
在每個 Git 倉庫中,標簽允許開發者標記特定的提交。標簽可以是 “輕量級的” —— 幾乎只是一個特定提交上的指針,或者它們可以是 “帶注釋的”,它自己將成為 git 樹中的項目。一個帶注釋標簽對象包含所有下列的信息:
- 成為標簽的提交的哈希的校驗和
- 標簽名字
- 關于打標簽的人的信息(名字、email、打標簽時間)
- 標簽信息
一個 PGP 簽名的標簽是一個帶有將所有這些條目封裝進一個 PGP 簽名的帶注釋標簽。當開發者簽名他們的 git 標簽時,他們實際上是向你保證了如下的信息:
- 他們是誰(以及他們為什么應該被信任)
- 他們在簽名時的倉庫狀態是什么樣:
- 標簽包含的提交的哈希
- 提交的哈希包含了頂級樹的哈希
- 頂級樹哈希包含了所有文件、內容和子樹的哈希
- 它也包含有關作者的所有信息
- 包含變更發生時的精確時間
- 標簽包含的提交的哈希
當你克隆一個倉庫并驗證一個簽名的標簽時,就是向你以密碼方式保證:倉庫中的所有內容、包括所有它的歷史,與開發者簽名時在它的計算機上的倉庫完全一致。
簽名的提交
簽名的提交與簽名的標簽非常類似 —— PGP 簽名的是提交對象的內容,而不是標簽對象的內容。一個提交簽名也給你提供了開發者簽名時開發者樹上的全部可驗證信息。標簽簽名和提交的 PGP 簽名提供了有關倉庫和它的完整歷史的完全一致的安全保證。
簽名的推送
為了完整起見,在這里包含了簽名的推送這一功能,因為在你使用這個功能之前,需要在接收推送的服務器上先啟用它。正如我們在上面所說過的,PGP 簽名一個 git 對象就是提供了開發者的 git 樹當時的可驗證信息,但不提供開發者對那個樹意圖相關的信息。
比如,你可以在你自己復刻的 git 倉庫的一個實驗分支上嘗試一個很酷的特性,為了評估它,你提交了你的工作,但是有人在你的代碼中發現了一個惡意的 bug。由于你的提交是經過正確簽名的,因此有人可能將包含有惡意 bug 的分支推入到 master 分支中,從而在生產系統中引入一個漏洞。由于提交是經過你的密鑰正確簽名的,所以一切看起來都是合理合法的,而當 bug 被發現時,你的聲譽就會因此而受到影響。
在 git push 時,為了驗證提交的意圖而不僅僅是驗證它的內容,添加了要求 PGP 推送簽名的功能。
配置 git 使用你的 PGP 密鑰
如果在你的鑰匙環上只有一個密鑰,那么你就不需要再做額外的事了,因為它是你的默認密鑰。
然而,如果你有多個密鑰,那么你必須要告訴 git 去使用哪一個密鑰。([fpr] 是你的密鑰的指紋):
$ git config --global user.signingKey [fpr]注意:如果你有一個不同的 gpg2 命令,那么你應該告訴 git 總是去使用它,而不是傳統的版本 1 的 gpg:
$ git config --global gpg.program gpg2如何使用簽名標簽
創建一個簽名的標簽,只要傳遞一個簡單地 -s 開關給 tag 命令即可:
$ git tag -s [tagname]我們建議始終對 git 標簽簽名,這樣讓其它的開發者確信他們使用的 git 倉庫沒有被惡意地修改過(比如,引入后門):
如何驗證簽名的標簽
驗證一個簽名的標簽,只需要簡單地使用 verify-tag 命令即可:
$ git verify-tag [tagname]如果你要驗證其他人的 git 標簽,那么就需要你導入他的 PGP 公鑰。請參考 “可信任的團隊溝通” 一文中關于此主題的指導。
在拉取時驗證
如果你從項目倉庫的其它復刻中拉取一個標簽,git 將自動驗證簽名,并在合并操作時顯示結果:
$ git pull [url] tags/sometag合并信息將包含類似下面的內容:
Merge tag 'sometag' of [url][Tag message]# gpg: Signature made [...] # gpg: Good signature from [...]配置 git 始終簽名帶注釋標簽
很可能的是,你正在創建一個帶注釋標簽,你應該去簽名它。強制 git 始終簽名帶注釋的標簽,你可以設置一個全局配置選項:
$ git config --global tag.forceSignAnnotated true或者,你始終記得每次都傳遞一個 -s 開關:
$ git tag -asm "Tag message" tagname如何使用簽名的提交
創建一個簽名的提交很容易,但是將它納入到你的工作流中卻很困難。許多項目使用簽名的提交作為一種 “Committed-by:” 的等價行,它記錄了代碼來源 —— 除了跟蹤項目歷史外,簽名很少有人去驗證。在某種意義上,簽名的提交用于 “篡改證據”,而不是 git 工作流的 “篡改證明”。
為創建一個簽名的提交,你只需要 git commit 命令傳遞一個 -S 標志即可(由于它與另一個標志沖突,所以改為大寫的 -S):
$ git commit -S我們建議始終使用簽名提交,并要求項目所有成員都這樣做,這樣其它人就可以驗證它們(下面就講到如何驗證)。
如何去驗證簽名的提交
驗證簽名的提交需要使用 verify-commit 命令:
$ git verify-commit [hash]你也可以查看倉庫日志,要求所有提交簽名是被驗證和顯示的:
$ git log --pretty=short --show-signature在 git 合并時驗證提交
如果項目的所有成員都簽名了他們的提交,你可以在合并時強制進行簽名檢查(然后使用 -S 標志對合并操作本身進行簽名):
$ git merge --verify-signatures -S merged-branch注意,如果有一個提交沒有簽名或驗證失敗,將導致合并操作失敗。通常情況下,技術是最容易的部分 —— 而人的因素使得項目中很難采用嚴格的提交驗證。
如果你的項目在補丁管理上采用郵件列表
如果你的項目在提交和處理補丁時使用一個郵件列表,那么一般很少使用簽名提交,因為通過那種方式發送時,簽名信息將會丟失。對提交進行簽名仍然是非常有用的,這樣其他人就能引用你托管在公開 git 樹作為參考,但是上游項目接收你的補丁時,仍然不能直接使用 git 去驗證它們。
盡管,你仍然可以簽名包含補丁的電子郵件。
配置 git 始終簽名提交
你可以告訴 git 總是簽名提交:
git config --global commit.gpgSign true或者你每次都記得給 git commit 操作傳遞一個 -S 標志(包括 —amend)。
配置 gpg-agent 選項
GnuPG agent 是一個守護工具,它能在你使用 gpg 命令時隨時自動啟動,并運行在后臺來緩存私鑰的密碼。這種方式讓你只需要解鎖一次密鑰就可以重復地使用它(如果你需要在一個自動腳本中簽署一組 git 操作,而不想重復輸入密鑰,這種方式就很方便)。
為了調整緩存中的密鑰過期時間,你應該知道這兩個選項:
- default-cache-ttl(秒):如果在 TTL 過期之前再次使用同一個密鑰,這個倒計時將重置成另一個倒計時周期。缺省值是 600(10 分鐘)。
- max-cache-ttl(秒):自首次密鑰輸入以后,不論最近一次使用密鑰是什么時間,只要最大值的 TTL 倒計時過期,你將被要求再次輸入密碼。它的缺省值是 30 分鐘。
如果你認為這些缺省值過短(或過長),你可以編輯 ~/.gnupg/gpg-agent.conf 文件去設置你自己的值:
# set to 30 minutes for regular ttl, and 2 hours for max ttl default-cache-ttl 1800 max-cache-ttl 7200補充:與 ssh 一起使用 gpg-agent
如果你創建了一個 A(驗證)密鑰,并將它移到了智能卡,你可以將它用到 ssh 上,為你的 ssh 會話添加一個雙因子驗證。為了與 agent 溝通你只需要告訴你的環境去使用正確的套接字文件即可。
首先,添加下列行到你的 ~/.gnupg/gpg-agent.conf 文件中:
enable-ssh-support接著,添加下列行到你的 .bashrc 文件中:
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)為了讓改變生效,你需要殺掉正在運行的 gpg-agent 進程,并重新啟動一個新的登入會話:
$ killall gpg-agent $ bash $ ssh-add -L最后的命令將列出代表你的 PGP Auth 密鑰的 SSH(注釋應該會在結束的位置顯示: cardno:XXXXXXXX,表示它來自智能卡)。
為了啟用 ssh 的基于密鑰的登入,只需要在你要登入的遠程系統上添加 ssh-add -L 的輸出到 ~/.ssh/authorized_keys 中。祝賀你,這將使你的 SSH 登入憑據更難以竊取。
此外,你可以從公共密鑰服務器上下載其它人的基于 PGP 的 ssh 公鑰,這樣就可以賦予他登入 ssh 的權利:
$ gpg --export-ssh-key [keyid]如果你有讓開發人員通過 ssh 來訪問 git 倉庫的需要,這將讓你非常方便。下一篇文章,我們將提供像保護你的密鑰那樣保護電子郵件帳戶的小技巧。
總結
以上是生活随笔為你收集整理的git推送密码_保护代码完整性(六):在 Git 上使用 PGP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bootstrap获取表格中选中行的值_
- 下一篇: int 为什么是2147483647_2