公众号关注 「奇妙的 Linux 世界」
设为「星标」,每天带你玩转 Linux !
Git 支持使用 GPG 来签名提交记录。但 GPG 用起来很复杂,一直赖得搞。
Git 从 2.34 开始支持使用 SSH 签名。SSH 密钥大家肯定都有,所以开启签名也需要提上日程了。只不过这个功能发布后很长时间内 GitHub 都不支持显示 SSH 签名,我也就没有继续推进。昨天 GitHub 官宣正式支持 SSH 签名。今天就把相关的内容整理一下分享给大家。
首先,为什么要对 Git 提交做签名呢?那是因为在 Git 中很容易伪造提交身份。
我们知道,Git 要求在提交前指定作者名字和邮箱:
git config user.name 涛叔
git config user.email [email protected]
但这两个配置可以随便填。任何人都可以声称自己是涛叔。为了保护自己的声誉,我可以用非对称加密技术对提交进行签名,然后公布自己公钥。这样其他人就可以根据这个公钥来验证 Git 变更是不是由我本人提交的。只要我不泄漏自己的私钥,别人就很难伪装成我来做坏事。
实现签名最常见的工具是 GPG。如果你玩过 Linux 肯定不陌生,很多发行版的包管理器都使用 GPG 对包做签名,防止坏人伪造。
但 GPG 对小白用户不友好,所以普通 Git 玩家很少会开启签名。一直到 OpenSSH 8.0 发布,局面才有所改观。因为这个版本的 OpenSSH 支持给任意数据进行签名。
签名功能在 OpenSSH 8.7 出问题了,建议使用 8.8 以后的版本
SSH 签名的工具是 ssh-keygen。估计很多人只在第一次生成 SSH 密钥的时候用到过,后面就在没碰过它了。虽然有点奇怪🤔但签名也验签功能也是由 ssh-keygen 提供的。
假设有一个文件/tmp/a.txt
,我们想使用~/.ssh/id_ed25519
给它做签名,我们可以:
ssh-keygen -Y sign -f ~/.ssh/id_ed25519 -n file /tmp/a.txt
各参数的功能如下:
-Y sign
表示计算签名-f
指定私钥-n file
是给签名指定类型file
是我们自己定的,不同类型的签名不会产生冲突
执行之后就会得到一个签名文件/tmp/a.txt.sig
,内容长这个样子:
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgulKNunkcVxiDzY0wmqJo4rAG9L
ClGRq9mMfA/PqsKYkAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
AAAAQP1FljU1ZQ327DZE11wjHIDgz1s0ULi7QO5rhg+MyEn12nwkV0fk69qDqmcpAE562x
pIxa+yaGuMV6hK97Hq+gE=
-----END SSH SIGNATURE-----
有了签名,我们就可以验证是不是有坏人篡改了文件内容了。验证签名需要一个公钥列表:
[email protected] ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILpSjbp5HFcYg82NMJqiaOKwBvSwpRkavZjHwPz6rCmJ ts@tc
...
第一列是公钥的标识,我们这里用的是邮箱。第二列是公钥类型,后面的部分是公钥内容,也就是~/.ssh/id_ed25519.pub
的内容。每个公钥占一行。
验签命令如下:
ssh-keygen -Y verify -f allowed_signers -I [email protected] -n file -s /tmp/a.txt.sig < /tmp/a.txt
各参数的功能如下:
-Y verify
表示要验证签名-f
用来指定公钥列表文件-I
指定使用公钥标识-n file
需要跟签名的时候保持一致-s
指定签名所在文件
最后通过重定向将文件内容传给 ssh-keygen。如果验证通过,则会得到如下结果:
Good "file" signature for [email protected] with ED25519 key SHA256:19/J4WKT7flBNcfmqQUqyAZeH4TdhMf5f0u+a4fZj1c
如果有人修改了文件内容,则会得到如下结果:
Signature verification failed: incorrect signature
Could not verify signature.
考虑到大多数 Git 用户都有自己的 SSH 密钥,不支持 SSH 签名岂不是很浪费?于是 Git 2.34 集成了 SSH 签名功能。
我们需要添加如下配置:
# 使用 SSH 签名
git config gpg.format ssh
# 指定 SSH 私钥文件
git config user.signingKey ~/.ssh/id_ed25519.pub
# 指定可信公钥列表文件
git config gpg.ssh.allowedSignersFile "$HOME/.config/git/allowed_signers"
# 开启自动签名(可选)
git config commit.gpgsign true
git config tag.gpgsign true
一番操作之后就准备好了。接下来所有的 Git 提交都会使用 SSH 签名。如果没有开启自动签名,则可以在提交的时候通过-s
参数来临时开启。
在默认配置下,我们看不出签名后的提交跟普通提交有什么区别。如果想展示签名信息,需要指定--show-signature
参数:
git show --show-signature |head
commit 6292a43f184e8a347b6c8b4fe08191920c0e22a5
Good "git" signature for [email protected] with ED25519 key SHA256:19/J4WKT7flBNcfmqQUqyAZeH4TdhMf5f0u+a4fZj1c
Author: 涛叔 <[email protected]>
Date: Wed Aug 24 07:55:54 2022 +0800
支持给 TS 的枚举类型生成 toString/parser 函数
diff --git a/autoload/lv.vim b/autoload/lv.vim
index 22a6b38..a08deb9 100644
--- a/autoload/lv.vim
...
这个时候我们就看到了Good "git" signatures ...
验证消息。
如果你使用 tig,也应该添加同样的参数,或者在~/.tigrc
中开启如下配置:
set log-options = --show-signature
set diff-options = --show-signature
回想我们前面的例子,当-n
的值为file
的时候,验签信息是Good "file"...
。现在的信息是Good "git"...
,说明 Git 使用的参数是-n git
。
但有个问题,Git 到底把签名信息存到了什么地方呢?答案是 commit 或者 tag 对应的 object。如果你不了解 Git 的存储模型,可以阅读我的另一篇文章。
我们可以使用cat-file
查看对象保存的内容:
$ git cat-file commit 6292a43f184e8a347b6c8b4fe08191920c0e22a5
tree c17c1e92312dc7303018c3dc3cd25d26007305e2
parent e71d24c876aa6e82a69e1566623083923edcab03
author 涛叔 <[email protected]> 1661298954 +0800
committer 涛叔 <[email protected]> 1661298954 +0800
gpgsig -----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgulKNunkcVxiDzY0wmqJo4rAG9L
ClGRq9mMfA/PqsKYkAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
AAAAQP1FljU1ZQ327DZE11wjHIDgz1s0ULi7QO5rhg+MyEn12nwkV0fk69qDqmcpAE562x
pIxa+yaGuMV6hK97Hq+gE=
-----END SSH SIGNATURE-----
支持给 TS 的枚举类型生成 toString/parser 函数
大家看 gpgsig 这一行,表示当前提交的签名信息。后面的每一行前面都有一个空格,表示这些行跟 gpgsig 是一个整体。
那 Git 是怎样签名的呢?我没有去看源码。但我猜是去掉 gpgsig 签名信息,然后对剩余的内容计算签名,签名类型为 git。于是我把对应的内容保存成文件签了一下,跟 gpgsig 的值完全一致。
Git 签名很好地解决了分装身份的问题。但如果对应功能没办法在 GitHub 上显示,那就不够炫酷。所以 Git 2.34 刚发布就有用户建议 GitHub 添加支持。昨天终于上线了😄
虽然 GitHub 支持展示 SSH 签名信息,但是签名和鉴权用的密钥需要分别上传。上传的时候需要指定类型。哪怕是使用同一个密钥也得额外再传一次。
上传公钥之后,GitHub 就会展示对应的 SSH 签名。
以上就是本文的全部内容,希望能给大家一些参考。欢迎留言讨论。
参与文献:
https://www.agwa.name/blog/post/ssh_signatures
https://blog.dbrgn.ch/2021/11/16/git-ssh-signatures/
https://git-scm.com/docs/signature-format
本文转载自:「 涛叔的博客 」,原文:https://url.hi-linux.com/155hC ,版权归原作者所有。欢迎投稿,投稿邮箱: [email protected]。
最近,我们建立了一个技术交流微信群。目前群里已加入了不少行业内的大神,有兴趣的同学可以加入和我们一起交流技术,在 「奇妙的 Linux 世界」 公众号直接回复 「加群」 邀请你入群。
你可能还喜欢
点击下方图片即可阅读
点击上方图片,『美团|饿了么』大额外卖红包天天免费领
更多有趣的互联网新鲜事,关注「奇妙的互联网」视频号全了解!