
Git 支持使用 GPG 來簽名提交記錄。但 GPG 用起來很復(fù)雜,一直賴得搞。
(資料圖)
Git 從 2.34 開始支持使用 SSH 簽名。SSH 密鑰大家肯定都有,所以開啟簽名也需要提上日程了。只不過這個功能發(fā)布后很長時間內(nèi) GitHub 都不支持顯示 SSH 簽名,我也就沒有繼續(xù)推進。昨天 GitHub 官宣正式支持 SSH 簽名。今天就把相關(guān)的內(nèi)容整理一下分享給大家。
首先,為什么要對 Git 提交做簽名呢?那是因為在 Git 中很容易偽造提交身份。
我們知道,Git 要求在提交前指定作者名字和郵箱:
gitconfiguser.name濤叔gitconfiguser.emailhi@taoshu.in
但這兩個配置可以隨便填。任何人都可以聲稱自己是濤叔。為了保護自己的聲譽,我可以用非對稱加密技術(shù)對提交進行簽名,然后公布自己公鑰。這樣其他人就可以根據(jù)這個公鑰來驗證 Git 變更是不是由我本人提交的。只要我不泄漏自己的私鑰,別人就很難偽裝成我來做壞事。
實現(xiàn)簽名最常見的工具是 GPG。如果你玩過 Linux肯定不陌生,很多發(fā)行版的包管理器都使用 GPG 對包做簽名,防止壞人偽造。
但 GPG 對小白用戶不友好,所以普通 Git 玩家很少會開啟簽名。一直到 OpenSSH 8.0 發(fā)布,局面才有所改觀。因為這個版本的 OpenSSH 支持給任意數(shù)據(jù)進行簽名。
簽名功能在 OpenSSH 8.7 出問題了,建議使用 8.8 以后的版本
SSH 簽名的工具是 ssh-keygen。估計很多人只在第一次生成 SSH 密鑰的時候用到過,后面就在沒碰過它了。雖然有點奇怪但簽名也驗簽功能也是由 ssh-keygen 提供的。
假設(shè)有一個文件/tmp/a.txt,我們想使用~/.ssh/id_ed25519給它做簽名,我們可以:
ssh-keygen-Ysign-f~/.ssh/id_ed25519-nfile/tmp/a.txt
各參數(shù)的功能如下:
-Y sign表示計算簽名
-f指定私鑰
-n file是給簽名指定類型
file是我們自己定的,不同類型的簽名不會產(chǎn)生沖突
執(zhí)行之后就會得到一個簽名文件/tmp/a.txt.sig,內(nèi)容長這個樣子:
-----BEGINSSHSIGNATURE-----U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgulKNunkcVxiDzY0wmqJo4rAG9LClGRq9mMfA/PqsKYkAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5AAAAQP1FljU1ZQ327DZE11wjHIDgz1s0ULi7QO5rhg+MyEn12nwkV0fk69qDqmcpAE562xpIxa+yaGuMV6hK97Hq+gE=-----ENDSSHSIGNATURE-----
有了簽名,我們就可以驗證是不是有壞人篡改了文件內(nèi)容了。驗證簽名需要一個公鑰列表:
hi@taoshu.inssh-ed25519AAAAC3NzaC1lZDI1NTE5AAAAILpSjbp5HFcYg82NMJqiaOKwBvSwpRkavZjHwPz6rCmJts@tc...
第一列是公鑰的標識,我們這里用的是郵箱。第二列是公鑰類型,后面的部分是公鑰內(nèi)容,也就是~/.ssh/id_ed25519.pub的內(nèi)容。每個公鑰占一行。
驗簽命令如下:
ssh-keygen-Yverify-fallowed_signers-Ihi@taoshu.in-nfile-s/tmp/a.txt.sig各參數(shù)的功能如下:
-Y verify表示要驗證簽名
-f 用來指定公鑰列表文件
-I 指定使用公鑰標識
-n file 需要跟簽名的時候保持一致
-s 指定簽名所在文件
最后通過重定向?qū)⑽募?nèi)容傳給 ssh-keygen。如果驗證通過,則會得到如下結(jié)果:
Good"file"signatureforhi@taoshu.inwithED25519keySHA256:19/J4WKT7flBNcfmqQUqyAZeH4TdhMf5f0u+a4fZj1c如果有人修改了文件內(nèi)容,則會得到如下結(jié)果:
Signatureverificationfailed:incorrectsignatureCouldnotverifysignature.考慮到大多數(shù) Git 用戶都有自己的 SSH 密鑰,不支持 SSH 簽名豈不是很浪費?于是 Git 2.34 集成了 SSH 簽名功能。
我們需要添加如下配置:
#使用SSH簽名gitconfiggpg.formatssh#指定SSH私鑰文件gitconfiguser.signingKey~/.ssh/id_ed25519.pub#指定可信公鑰列表文件gitconfiggpg.ssh.allowedSignersFile"$HOME/.config/git/allowed_signers"#開啟自動簽名(可選)gitconfigcommit.gpgsigntruegitconfigtag.gpgsigntrue一番操作之后就準備好了。接下來所有的 Git 提交都會使用 SSH 簽名。如果沒有開啟自動簽名,則可以在提交的時候通過-s參數(shù)來臨時開啟。
在默認配置下,我們看不出簽名后的提交跟普通提交有什么區(qū)別。如果想展示簽名信息,需要指定--show-signature參數(shù):
gitshow--show-signature|headcommit6292a43f184e8a347b6c8b4fe08191920c0e22a5Good"git"signatureforhi@taoshu.inwithED25519keySHA256:19/J4WKT7flBNcfmqQUqyAZeH4TdhMf5f0u+a4fZj1cAuthor:濤叔Date:WedAug2407542022+0800支持給TS的枚舉類型生成toString/parser函數(shù)diff--gita/autoload/lv.vimb/autoload/lv.vimindex22a6b38..a08deb9100644---a/autoload/lv.vim...這個時候我們就看到了Good "git" signatures ...驗證消息。
如果你使用 tig,也應(yīng)該添加同樣的參數(shù),或者在~/.tigrc中開啟如下配置:
setlog-options=--show-signaturesetdiff-options=--show-signature回想我們前面的例子,當-n的值為file的時候,驗簽信息是Good "file"...。現(xiàn)在的信息是Good "git"...,說明 Git 使用的參數(shù)是-n git。
但有個問題,Git 到底把簽名信息存到了什么地方呢?答案是 commit 或者 tag 對應(yīng)的 object。如果你不了解 Git 的存儲模型,可以閱讀我的另一篇文章。
我們可以使用cat-file查看對象保存的內(nèi)容:
$gitcat-filecommit6292a43f184e8a347b6c8b4fe08191920c0e22a5treec17c1e92312dc7303018c3dc3cd25d26007305e2parente71d24c876aa6e82a69e1566623083923edcab03author濤叔1661298954+0800committer濤叔1661298954+0800gpgsig-----BEGINSSHSIGNATURE-----U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgulKNunkcVxiDzY0wmqJo4rAG9LClGRq9mMfA/PqsKYkAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5AAAAQP1FljU1ZQ327DZE11wjHIDgz1s0ULi7QO5rhg+MyEn12nwkV0fk69qDqmcpAE562xpIxa+yaGuMV6hK97Hq+gE=-----ENDSSHSIGNATURE-----支持給TS的枚舉類型生成toString/parser函數(shù)大家看 gpgsig 這一行,表示當前提交的簽名信息。后面的每一行前面都有一個空格,表示這些行跟 gpgsig 是一個整體。
那 Git 是怎樣簽名的呢?我沒有去看源碼。但我猜是去掉 gpgsig 簽名信息,然后對剩余的內(nèi)容計算簽名,簽名類型為 git。于是我把對應(yīng)的內(nèi)容保存成文件簽了一下,跟 gpgsig 的值完全一致。
Git 簽名很好地解決了分裝身份的問題。但如果對應(yīng)功能沒辦法在 GitHub 上顯示,那就不夠炫酷。所以 Git 2.34 剛發(fā)布就有用戶建議 GitHub 添加支持。昨天終于上線了
雖然 GitHub 支持展示 SSH 簽名信息,但是簽名和鑒權(quán)用的密鑰需要分別上傳。上傳的時候需要指定類型。哪怕是使用同一個密鑰也得額外再傳一次。
上傳公鑰之后,GitHub 就會展示對應(yīng)的 SSH 簽名。
以上就是本文的全部內(nèi)容,希望能給大家一些參考。歡迎留言討論。
審核編輯:湯梓紅
標簽: