导入有毒密钥后如何修复 GnuPG(而不是直接删除它)

导入有毒密钥后如何修复 GnuPG(而不是直接删除它)

我的 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:~$ 

上面的输出表明

  1. 2019 年 6 月 17 日,共有 14,400 人签署了该密钥,
  2. 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 客户端自行崩溃:

  1. 删除“gpg.conf”文件中以“keyserver”开头的所有行,然后
  2. 更新“dirmngr.conf”以便它只有 1 个“keyserver” =“keyserver hkps://keys.openpgp.org”

keys.openpgp.org密钥服务器是一个新的实验性服务器(有趣的是,它是在这些被毒害的证书上传前几周才上线的),它对这些攻击的抵抗力更强。请注意,它所服务的证书完全缺乏第三方签名,并且它还会从密钥中剥离 UID 数据包,除非用户明确选择加入

6. 更新您的 MUA 配置

您可能还需要更新您的 MUA。例如,thunderbird 中的 enigmail 可能也需要配置为更新密钥环中的密钥。

为了防止 enigmail 从密钥服务器刷新您的密钥,请转到 thunderbird 首选项 -> 高级 -> 配置编辑器... -> 我接受风险!

并设置extensions.enigmail.keyRefreshOnfalse

附录

请注意,密钥箱密钥环格式将拒绝导入被污染的密钥,因为它具有最大密钥大小5 MiB,并且拥有旧安装的用户应该考虑将其密钥环迁移到密钥箱格式。

这可以在基于 Debian 的系统中轻松完成,使用从经典 gpg 迁移 pubring命令

答案2

但是,如何才能在本地清理公钥而不需要下载新的副本(这会引入不必要的篡改向量)?

未经测试的方法:

  1. 跑步gpg --edit-key <keyid> clean save

另一种方法:

  1. 使用将密钥(或所有密钥)导出到文件--export-options export-clean(这将跳过无法根据密钥环中受信任的密钥验证的所有签名)。
  2. 删除该项。
  3. 从您之前制作的文件中导入密钥。

还有一种方法:

  1. 写下密钥的指纹(全长指纹,而不仅仅是 16 位“密钥 ID”)。
  2. 删除该项。
  3. 根据指纹下载一份新副本(--keyserver-options self-sigs-only如果您选择使用密钥服务器,则这次使用)。

相关内容