为什么Git需要有签名推送?

27
Git 2.2.0 的发行说明中,它描述了一个新选项 --signed 用于 git push:
"git push" learned "--signed" push, that allows a push (i.e.
request to update the refs on the other side to point at a new
history, together with the transmission of necessary objects) to be
signed, so that it can be verified and audited, using the GPG
signature of the person who pushed, that the tips of branches at a
public repository really point the commits the pusher wanted to,
without having to "trust" the server.

听起来数据在推送过程中发送到服务器时是经过签名的,以便服务器可以验证并记录谁进行了推送。您可以在man页面中确认此内容:

--signed
   GPG-sign the push request to update refs on the receiving side, 
   to allow it to be checked by the hooks and/or be logged. See 
   git-receive-pack[1] for the details on the receiving end.

你需要在 git-receive-packpre-receivepost-receive hooks 页面查看如何验证已签名的推送。

似乎所有这些都有助于服务器验证推送者的身份是否真实。

git push --signed 如何帮助你(推送者)不必“信任”服务器? 到目前为止,我所见的一切都表明它有助于服务器信任你。更重要的是,为什么签名提交和签名标签不足以向不受信任的服务器推送?我们为什么需要签名推送?

3个回答

20

以下是介绍签名推送的提交信息摘录:

尽管签名标签和提交断言已签署的对象来自于您,但没有很好的方法来确认您想要将特定对象放在特定分支的顶部。我的签名v2.0.1标签仅意味着我想要将版本v2.0.1称为这个,而不意味着我想要将其推送到我的'master'分支——我可能只想要它在'maint'中,因此仅对象上的签名是不够的。

对于您的唯一保证是'maint'指向我想要放置的内容,取决于您对托管站点的信任和我的身份验证,这在以后无法轻松审计。

因此,尽管提交已经签名,您也无法确定作者打算将该提交推送到分支master还是分支super-experimental-feature。签名推送允许服务器记录每个推送事件及其签名。然后可以验证此日志以查看每个提交确实打算在特定分支上。

1

初步讨论在这里,针对Git 2.2(2014年第四季度)
其中包括:

每行显示了此次推送尝试更新的引用端点上的旧对象名称和新对象名称,方式与底层的 "git push" 协议交换告诉接收端更新引用的方式相同(通过记录“旧”对象名称,推送证书还可防止重播)。它还在一个新的“pushee URL”头中记录了推送的预期接收方的URL(如果它具有身份验证材料,则匿名化),该值可能不可靠地用于重放攻击预防目的,但仍将作为人类可读提示,以确定证书所指的存储库。为了防止有效的推送证书被重放到不相关的存储库中进行推送,请从receive-pack过程发送nonce字符串,并让签名者在推送证书中包含它。接收端使用服务的存储库路径和当前时间的HMAC哈希(使用秘密密钥散列,这不必是每个存储库的设置,而可以在/etc/gitconfig中定义)来确保随机第三方不能伪造看起来像它来自的nonce。

自Git 2.2(2014年)以来,更近期的补丁突出了上述“提交重放预防技术”:

尽管签名推送确实允许服务器记录每个推送事件及其签名,但在Git 2.19(2018年第三季度)之前,它可能无法记录正确的用户:

git send-pack --signed”(因此通过http传输的“git push --signed”)未从配置机制中读取用户标识以确定应将哪些人作为推送证书进行签名,这已得到纠正。

请查看 提交记录 d067d98 (2018年6月12日) 由 Masaya Suzuki (draftcode) 提交。
(由 Junio C Hamano -- gitster --提交记录 8d3661d 中合并,日期为2018年6月28日)

builtin/send-pack: 填充默认配置

builtin/send-pack 没有调用 git_default_config,因此在 HTTP 传输中,git push --signed 不会尊重 gitconfig 中的用户名和电子邮件。


自 Git 2.27(2020年第二季度)起,推送证书的验证已经更加强化,以防止时间攻击。

请查看由Junio C Hamano(gitster于2020年4月22日提交的提交719483e
请查看由brian m. carlson(bk2204于2020年4月9日提交的提交edc6dcc
(合并自Junio C Hamano -- gitster --提交2abd648中,2020年4月28日)

builtin/receive-pack: 使用恒定时间比较HMAC值

Signed-off-by: brian m. carlson

当我们比较推送证书nonce时,我们目前使用的是strcmp。大多数strcmp的实现会在确认两个值是否相等后立即短路退出。 然而,当我们比较HMAC的输出时,这是一个问题,因为如果它们确实不同,它会在时间上泄漏有多少内容匹配了两个值。 在我们的情况下,nonce用于通过嵌入的时间戳防止对我们的服务器进行重放攻击,并通过HMAC使用来自不同服务器的请求进行重放攻击。 包含nonces的推送证书已签名,因此攻击者无法篡改nonces而不破坏签名验证。 当然,他们可以创建自己的具有无效nonces的签名,但他们也可以创建自己的具有有效nonces的签名,因此没有什么可获得的。 因此,没有安全问题。 尽管从当前技术中似乎没有任何负面影响,但出于安全性和鼓励良好实践的考虑,让我们使用一种常量时间比较函数来进行nonce验证。POSIX并没有提供这样的函数,但编写起来很容易。 我们在这里使用的技术也被用于NaCl和Go标准库,并依赖于按位或和异或在所有已知架构上都是常量时间。 我们不必担心如果实际长度和期望长度不同就提前退出,因为标准加密假设是每个人都知道我们的nonces的格式和算法(在任何情况下,他们都有源代码并且可以轻松确定)。 因此,我们假设每个人都知道我们的nonces应该有多长。 当在HMAC值上执行常量时间比较时,这种哲学也被Go标准库和其他加密库采用。

0

简短的回答是,git push --signed 的目的是为了防止提交重放攻击。

如果您将未经测试/不安全的代码的签名提交推送到 experimental 分支,那么其他人可以将该提交重放到 master 分支,并且它仍然会显示为由您签名,即使您从未打算将该代码推送到 master 分支。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接