![导入有毒密钥后如何修复 GnuPG(而不是直接删除它)](https://linux22.com/image/1597341/%E5%AF%BC%E5%85%A5%E6%9C%89%E6%AF%92%E5%AF%86%E9%92%A5%E5%90%8E%E5%A6%82%E4%BD%95%E4%BF%AE%E5%A4%8D%20GnuPG%EF%BC%88%E8%80%8C%E4%B8%8D%E6%98%AF%E7%9B%B4%E6%8E%A5%E5%88%A0%E9%99%A4%E5%AE%83%EF%BC%89.png)
我的 GnuPG 客户端自动从密钥服务器刷新了密钥环中的密钥,并导入了被毒害的密钥。我该如何修复密钥环而不只是删除被毒害的公钥?
上个月备受瞩目的 pgp 证书遭到攻击通过证书泛滥攻击 (CVE-2019-13050) 通过向他们的公钥发送数万个(或数十万个)签名并将其有毒的公钥上传到密钥服务器来实施攻击。
例如,如果你有“Tor 浏览器开发者(签名密钥)“在你的密钥环中,并且你在 2019-06-30 之后尝试--refresh-keys
从密钥服务器(当时他们的密钥被 121,000 个虚假签名淹没)发送,那么你的 gpg(以及你的电子邮件,例如,如果你使用带有 enigmail 的 thunderbird)将挂起并无法使用。
大部分的覆盖范围的这个问题说解决方案只是删除密钥——但是如何才能在本地清理公钥而不必下载新的副本(这会引入不必要的篡改向量)?
答案1
我花了一些时间研究如何解决这个问题,然后我在我的网站上发表了一篇关于它的文章。下面是此题解答的总结。
1. 识别被毒害的密钥
首先,我们可以使用以下命令列出密钥环中公钥的大小(以字节为单位)(如下已报告在 GnuPG 问题跟踪器上):
user@disp1754:~$ gpg --export | gpg --list-packets | awk -F= -v oldoff=-1 -v keyid=unset '
/^# off=/{ off = $2 + 0 }
/^:public key/{ if (oldoff>-1) { print (off - oldoff) " " keyid }; oldoff = off; keyid = "unset"; }
/keyid:/ {if (keyid == "unset") { keyid = $1; } }
END { print (off - oldoff) " " keyid ; };' | sort -n
7284 keyid: 1DCBDC01B44427C7
119748 keyid: 4E2C6E8793298290
124557 keyid: 403C2657CD994F73
16934647 keyid: F20691179038E5C6
user@disp1754:~$
如果上述命令运行时间超过几秒钟,则说明存在问题。等待 20 分钟左右,您会在底部看到有问题的键。任何包含 8 位数字(>10 MB)的内容都是危险信号。
ⓘ 注意:在上面的例子中,我们看到 id = 的公钥的
F20691179038E5C6
大小为16934647
字节 = 16M。这是我们的毒害密钥。本文后面的命令使用此
keyid
(F20691179038E5C6
) 来操作密钥环。您应该将以下命令中的此字符串替换为keyid
计算机上上述命令中的相应字符串。
2. 导出被毒害的密钥
现在我们已经确定了中毒密钥,在删除它之前,让我们将其导出以确保安全。
user@disp1754:~$ time gpg -a --export 'F20691179038E5C6' > pubkey.asc
real 3m30.950s
user 3m24.430s
sys 0m0.322s
user@disp1754:~$ du -sh pubkey.asc
22M pubkey.asc
user@disp1754:~$
几分钟后,命令将完成,您将得到一个以pubkey.asc
被污染的公钥内容命名的文件。请注意,这个只包含一个公钥的 ASCII 装甲文件大小为 22M!
3. 删除有毒密钥
现在我们在磁盘上已经有了中毒密钥的安全备份,让我们将其从密钥环中删除。
user@disp1754:~$ time gpg --delete-key 'F20691179038E5C6'
gpg (GnuPG) 2.1.18; Copyright (C) 2017 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
pub ed25519/F20691179038E5C6 2019-01-19 Daniel Kahn Gillmor <[email protected]>
Delete this key from the keyring? (y/N) y
real 12m15.265s
user 11m54.242s
sys 0m0.715s
user@disp1754:~$
4.重新导入已清理的密钥
要重新导入公钥的干净副本,我们将使用以下gpg
参数--import-filters
放弃所有签名(drop-sig
)是在证书上有大量签名的日期完成的。
给定一个公钥文件(比如我们上面刚刚导出的备份),我们可以使用以下命令列出该证书每天收到的签名数量:
user@disp1754:~$ time gpg --list-packets pubkey.asc | grep -i 'sig created ' | sort -n | uniq -c
11 hashed subpkt 2 len 4 (sig created 2019-01-19)
2 hashed subpkt 2 len 4 (sig created 2019-01-20)
4 hashed subpkt 2 len 4 (sig created 2019-01-21)
2 hashed subpkt 2 len 4 (sig created 2019-01-28)
14400 hashed subpkt 2 len 4 (sig created 2019-06-17)
40200 hashed subpkt 2 len 4 (sig created 2019-06-18)
real 0m23.061s
user 0m17.803s
sys 0m0.150s
user@disp1754:~$
上面的输出表明
- 2019 年 6 月 17 日,共有 14,400 人签署了该密钥,
- 2019 年 6 月 18 日,已有 40,200 人对该密钥进行了签名
我们可以导入密钥,同时省略这两天的这些垃圾签名,如下所示(请确保将日期替换为机器上上述命令打印的相应日期):
user@disp1754:~$ time gpg --import-filter drop-sig="sig_created_d=2019-06-17 || sig_created_d=2019-06-18" --import pubkey.asc
gpg: key F20691179038E5C6: 54614 signatures not checked due to missing keys
gpg: key F20691179038E5C6: public key "Daniel Kahn Gillmor <[email protected]>" imported
gpg: Total number processed: 1
gpg: imported: 1
gpg: no ultimately trusted keys found
real 3m12.091s
user 3m6.991s
sys 0m0.284s
user@disp1754:~$
现在事情应该更加合理了:
user@disp1754:~$ time gpg --export | gpg --list-packets | awk -F= -v oldoff=-1 -v keyid=unset '
> /^# off=/{ off = $2 + 0 }
> /^:public key/{ if (oldoff>-1) { print (off - oldoff) " " keyid }; oldoff = off; keyid = "unset"; }
> /keyid:/ {if (keyid == "unset") { keyid = $1; } }
> END { print (off - oldoff) " " keyid ; };' | sort -n
7284 keyid: 1DCBDC01B44427C7
8930 keyid: F20691179038E5C6
119748 keyid: 4E2C6E8793298290
124557 keyid: 403C2657CD994F73
real 0m0.063s
user 0m0.059s
sys 0m0.016s
user@disp1754:~$ gpg -a --export '403C2657CD994F73' > pubkey2.asc
user@disp1754:~$ du -sh pubkey2.asc
168K pubkey2.asc
user@disp1754:~$
5. 更新你的 GnuPG 配置
正如 Robert J. Hansen(其 pgp 密钥于 2019-06-19 被 149,100 个签名发送)在其出色的综合报告中指出的那样要旨关于此问题,您可以通过以下方式防止 gpg 客户端自行崩溃:
- 删除“gpg.conf”文件中以“keyserver”开头的所有行,然后
- 更新“dirmngr.conf”以便它只有 1 个“keyserver” =“keyserver hkps://keys.openpgp.org”
该keys.openpgp.org
密钥服务器是一个新的实验性服务器(有趣的是,它是在这些被毒害的证书上传前几周才上线的),它对这些攻击的抵抗力更强。请注意,它所服务的证书完全缺乏第三方签名,并且它还会从密钥中剥离 UID 数据包,除非用户明确选择加入。
6. 更新您的 MUA 配置
您可能还需要更新您的 MUA。例如,thunderbird 中的 enigmail 可能也需要配置为更新密钥环中的密钥。
为了防止 enigmail 从密钥服务器刷新您的密钥,请转到 thunderbird 首选项 -> 高级 -> 配置编辑器... -> 我接受风险!
并设置extensions.enigmail.keyRefreshOn
为false
附录
请注意,密钥箱密钥环格式将拒绝导入被污染的密钥,因为它具有最大密钥大小5 MiB,并且拥有旧安装的用户应该考虑将其密钥环迁移到密钥箱格式。
这可以在基于 Debian 的系统中轻松完成,使用从经典 gpg 迁移 pubring命令
答案2
但是,如何才能在本地清理公钥而不需要下载新的副本(这会引入不必要的篡改向量)?
未经测试的方法:
- 跑步
gpg --edit-key <keyid> clean save
。
另一种方法:
- 使用将密钥(或所有密钥)导出到文件
--export-options export-clean
(这将跳过无法根据密钥环中受信任的密钥验证的所有签名)。 - 删除该项。
- 从您之前制作的文件中导入密钥。
还有一种方法:
- 写下密钥的指纹(全长指纹,而不仅仅是 16 位“密钥 ID”)。
- 删除该项。
- 根据指纹下载一份新副本(
--keyserver-options self-sigs-only
如果您选择使用密钥服务器,则这次使用)。