2021年,用更现代的方法使用PGP(下)

公钥的发布与交换

Posted by UlyC on January 26, 2021

世界上有两种密码:一种是防止你的小妹妹偷看你的文件;另一种是防止当局阅读你的文件.

​ —— Bruce Schneier《应用密码学》

2021年,用更现代的方法使用PGP(下)

上篇链接:

2021年,用更现代的方法使用PGP(上) 2021年,用更现代的方法使用PGP(中)

PGP 公钥的 发布 与 交换

讨论公钥安全交换的中文文章比较少,而这一环是整个加密体系的重中之重。 大部分的PGP教程最后一步就是让小白用户将公钥上传,这是非常过时,且不负责任的,所以这里来详细介绍下PGP 公钥的 发布 与 交换。

原则

首先明确一点: 上传公钥到 公钥服务器 不是必要的,甚至是危险的。

如果你是新手,请不要发布你的公钥到 公钥服务器。

引子

通过前文,你已经熟悉了gpg的本地使用, 并且生成了自己的PGP 密钥对。

想象一下, 如果你生活在1980年代, 想和远方的朋友加密通信,需要先交换彼此的公钥,又没有一个统一的可信的认证机构,这时会有什么问题?

当面交换吗?当然是个办法,但是相信你不会想要将下列

1609751914957

这么长的公钥抄写到纸上,然后开车送到朋友那里,再让朋友照着这个输入他的电脑。如果中间有变动,需要重复以上过程n次。

那么还有其他办法吗?

那个时代还没有line、wechat这类即时通讯软件,而邮件提供商默认是不可靠的,不然也不会有PGP的诞生。 并且彼时https还未出现,用邮件交换PGP交换公钥显然不太安全。

你们双方都需要便捷地交换公玥, 并且确认彼此得到的公钥确实是未经篡改过的,真实有效的,就成了一个难题,这样,公钥服务器也就呼之欲出了。

公钥服务器 KeyServer

公钥服务器使得人们只需要交换他们短短的key id 或者user id就可以方便地从公钥服务器下载公钥。

历史与设计初衷

第一个KeyServer 叫做 HKP( web-based OpenPGP HTTP Keyserver Protocol) Keyserver , 诞生在上世纪90年代,是Marc Horowitz在麻省理工学习时为了他的论文而搭建的。在此之前, 虽然不是那么安全, 但是大部分人依靠电子邮件来交换公钥。

虽然服务器有了, 但开发者们担心政府会试图强迫密钥服务器运营商用政府选择的各种证书来替换证书。

所以他们做出了一个决定:公钥服务器永远不会删除信息。公钥服务器可以为现有的证书添加信息(比如可以revoke/sign或者调整expire时间),但永远永远永远不会删除证书或证书的信息。

为了达到这个目标,他们开始运行一个分布式的国际公钥服务器网络,这就是现在的KeyServer。世界各地的公钥服务器会定期相互通信,同步,比较目录。如果政府强迫公钥服务器运营商删除或修改证书,那么在比较步骤中就会被发现。残缺的公钥服务器会用完好密钥服务器目录中的内容更新自己。

任何东西都不会被删除,听起来很美好,也是解决政府审查问题的一个简单而有效的办法,可是正是这个原则后来给KeyServer带来了无穷无尽的问题。

信任网络 (Web of Trust)

好了,现在我们有了一个可以方便地上传和下载公钥的地方, 这样是不是就万事大吉了呢?

对于KeyServer 来说,任何人都可以上传公钥并声称自己是Linus, 是Zuckerberg,或是任何其他人,而KeyServer并不会去验证你是否是你所声称的人(因为KeyServer本来就没有一个中心化的运营者)。

如果你有一些密码学的基础, 那么就会知道, PGP协议依靠的非对称加密算法, 最脆弱的点就在于公钥的交换这一步。公钥交换时最容易收到中间人攻击,你一定要确定你接收到的公钥确实是你想交流的人的,由此TSL引入了CA证书认证体系,由一个可信的权威第三方来认证并颁发证书来解决身份的认证问题。 (具体可参见https系列没那么浅地谈谈HTTP与HTTPS)。

“信任一个权威的第三方” 对于最初的极具有hack精神的开发者们来说, 显然是无法接受的。

当然,你可以说下载公钥后,通过电话等手段验证下公钥的指纹(fingerprint),就可以确认正确与否。 但是想象一下, 如果你在公钥服务器找到一个声称自己Linus Torvalds 的人, 你并没有他的其他联系方式,将永远无法确定这个公钥持有者到底是谁、这个公钥可信与否 , 这样无疑是低效的,并且使整个系统沦为了熟人之间的小网络。

要知道,根据六度分隔理论(Six Degrees of Separation),世界上任何互不相识的两人,平均通过六个人就可以产生联系。 那么可以不可以这么思考, 假设我和小A见过面并检查过他的公钥,因而知道小A的公钥的的确确属于他本人,我选择信任小A。而小A同样验证了小B的证书并为小B的证书签名背书——小A的证书的持有人在此证明该证书是真实属于小B。那么我无须见亲见小B本人,也可以通过小A的背书而接受小B的证书。

如此循环下去,就形成了一张网, 这就是信任网络。

主流公钥服务器

1. SKS Keyserver Pool

当今世界最大的Key Server 池, 符合它的标准的世界各地的公钥服务器会定期相互通信,同步,比较目录,数据完全开放下载。 现在一般说起KeyServer说的就是这个。

KeyServer虽然一直是PGP的重要基础设置 ,但SKS Keyserver Pool 其实目前只有不到20台服务器,GnuPG默认用的服务器是其中的 HKPS pool,只有四台服务器。

2. Base Modern Software KeyServer

有一些KeyServer 没有用SKS的软件,运行的是更下现代和稳定的软件,比较有代表性的是 Ubuntu keyserver, 基于Hockeypuck , 这些服务器仍然会和SKS pool保持同步。

3. 独立KeyServer

这些服务器不与SKS pool同步数据,由中心化的运营者运行, 会对公钥上传者做一定的认证, 并且支持删除自己的公钥。

比较有代表性的有, keys.openpgp.org ,KeyBase等等。

在gpg中使用

发布

gpg   --send-keys  {keyid/uid}

下载

gpg --recv-keys {keyid/uid}

此时有可能报错

gpg: "xxxxxr" not a key ID: skipping

这时换个KeyServer就行:

gpg  --keyserver hkps://keyserver.ubuntu.com --recv-keys {keyid/uid}

签名和验证 他人公钥

验证公钥真实性 依靠多渠道确认的 公钥指纹。

一般来说为别人的公钥签名后,需要发还给他,或者发到公钥服务器(最好经过本人同意)。

gpg --sign-key  {keyid/uid}   # 为已经导入的 他人钥签名, 你为他签名,意味着你将为他的身份真实性背书,请谨慎 

高级设置

因为并不推荐大家使用KeyServer,所以这里只列举了基础操作。

如果你决定使用KeyServer的话,可以参考 OpenPGP 最佳实践 - 密钥服务器设置你的客户端与服务器通信使用 HKPS (HKP On SSL)协议, 并定期更新从服务器下载的公钥。

安全风险和争议, 被玩坏的KeyServer

在20世纪90年代初,开发者们怀着对技术的信心和人性的希望,期望创建一个友善 、纯粹、没有审查的净土, 在当时背景下,KeyServer不能删除任何已上传的东西,听起来是美好的,设计似乎是合理的。

但是事实是,网络匿名环境中充满了不那么友好的, 甚至是恶意的使用者,在当今看来 ,KeyServer这个系统并不健壮,问题重重,许多问题已经被发现十多年,而且无望解决。

滥用

按照官方推荐, UID (User ID) 是用来存储用户信息的,应该在里面填上你的名字和邮箱,一个 GPG 帐号下可以有若干个 UID。

而其实这个UID是没有任何强制限制的,也就是说你可以在UID中放入任何东西,可以是小说片段,可以是磁力链接,可是以编码后的图像、音频或视频……

1609913349212

当上传到KeyServer时, UID限制了2k的字符 . 以至于有人写了个用KeyServer存文件的项目keyserver-fs)

再次想象一下,你往网盘传了一个文件,共享给其他人,全世界的人都可以往这个网盘文件中添加文件,而且永远无法删除,情况会变得有多糟糕。

脆弱的KeyID

见过一些生成 PGP“靓号”的工具,就是指定你喜欢的ID规则,工具会暴力生成PGP密钥, 从中返回给你想要的密钥。

由此很容易想到,若攻击者知道了目标的KeyID, 完全可以通过工具来生成完全一样的KeyID(这就是碰撞), 并上传到KeyServer,来冒充目标。

而伪造一个KeyID有多容易呢,有研究人员借助scallion程序,使用了普通的GPU(Nvidia GeForce GTX)进行碰撞,花了4秒的时间就生成了一个指定的32 bit的 KeyID。

官方推荐公布自己的KeyID时,最少应该公布64 bit(也就是长16位16进制数啦 ),但是研究表明64 bit的KeyID也是可以 被碰撞的。

投毒

公钥服务器任何人都可以上传公钥,甚至你可以上传别人的公钥,比如你可以将自己签名过的别人的公钥,再次上传到KeyServer。

签名Dos

在WOT认证体系的设计中, 当客户端收到一份未知证书时,它应当从公钥服务器拉取所有为这张证书签过名的人的证书,逐层上溯,看看是否能够找到一张已经被用户信任的证书。如果能的话,就视信任这张为可信的。

2019年6月,有攻击者恶意向公钥服务器提交了对两个著名网友的签名背书。此事件中的受害者 Robert J. Hansen 的证书就被签名了 15000 次。因而任何人的 GPG 在尝试验证他的证书时,都会拉取 15000 个签名。而 GPG 在验证这么多签名的过程中会卡住很久。

由于被攻击的两个人在 GPG 社区中中地位很高,他们在 GPG 信任网络中处于相当核心的位置。这意味着——当你验证任意一份证书的时候,有不小的概率你会不小心拉取到他们俩的证书,然后你的 GPG 就会卡住。不但他们俩的证书没法用了,他们俩签名过的证书也都面临危险,乃至于他们俩签名过的证书所签名的证书……

而上传到KeyServer的所有东西都是不可删除的…为了解决这个问题, GnuPG 2.2.17 LWN.net 开始, 从KeyServer下载公钥时默认不再下载关联的公钥, 如果你想要感受证书DoS攻击的话,可以在设置中开启:

# ~/.gnupg/gpg.conf
keyserver-options no-self-sigs-only,no-import-clean
爆破

有个很厉害的程序媛Yegor Timoshenko(前面的SKS文件存储项目也是她的杰作),写了个工具SKS-Exploit,可以将任何人的PGP公钥损坏,变得不可导入。

这个工具同时还可以给任意人的公钥 追加伪造的UID(不是KeyID),并骗过KeyServer。

1609914787731

另外能直接让KeyServer宕机。

隐私问题

讽刺的是, 最初为了保护人们隐私而生的PGP , 却因为不能满足保护隐私的法规GDPR ,而使一个公开的 SKS 公钥服务器在欧洲处于违法状态(GDPR规定: 服务商必须提供删除个人信息的选项)。

许多新手按照教程提示的在创建PGP 密钥的时候填上了自己的真实姓名,并按照那些教程将公钥上传到了KeyServer,在人肉社工猖獗的今天,简直是个灾难。

我试着在KeyServer搜过一些博客作者留下的PGP Key, 不乏有些比较注重自身隐私的,可是他们大部分都将自己真实的名字(汉字或拼音)和邮箱一起发到了服务器上,要知道那里的数据是公开且永远不能删除的。 也有些人意识到问题之后revoke了带有真实姓名的公钥,可是仍然可以查到,并且变得更加显眼(revoke过的key会变红)。

其他发布公钥的方法

1. WKD(Web Key Directory)

WKD 的工作过程是 ,通过邮箱客户端 在域名服务器检查一个”well known” 的URL, 如果匹配到了邮箱地址对应的公钥,会使用https下载,并且不需要用户进行其他操作。用户不需要gpg 命令行等等复杂操作,让PGP加密回归单纯的邮件加密本身,用起来有些像S/MIME,但其实不一样。

比如这样一个URL: https://intevation.de/.well-known/openPGPkey/hu/g8td9rsyatrazsoiho37j9n3g5ypp34h 就对应 “aheinecke@intevation.de”这个邮箱地址。

这是通过Gpg4win的使用的一个示例,

[Example from Gpg4win / GpgOL](https://files.intevation.de/users/aheinecke/wkd-autoencrypt.gif)

这种方法不会泄露自己的邮箱,也不需要验证指纹, 但是需要你的邮件服务商提供支持。

proton邮箱是原生支持 WKD的, 但是它使用的是自己私钥,似乎没办法使用使用自己本地的公钥,其他也有支持。

如果你有自己的邮箱服务器,并且想折腾的话,可以参照WKD Hosting

2. 当面交换

如果是和熟识的朋友,你可以约在任何合适地方,用你喜欢的方式交换密钥, 比如交换纸条,交换TF卡 或者usb设备,互相签名认证,互相得到公钥。

如果是想认识更多的人,并让自己的公钥被更多的人认证, 你可以参加「公钥签名派对(Key signing party)」。参与派对的人们相互交换公钥的指纹(公钥一般是存在服务器或是一个别人可以下载到的地方,这里只交换指纹),甚至需要相互出示身份证、护照、驾照、出身证明,以验明正身。

Key signing in front of FOSDEM 2008

3. DNS

有很多种方法将你的公钥通过DNS服务发布,但是有些一些方法只适用于老版本的GnuPG,有些方法只适用与新版本的GnuPG,兼容性不佳,而且搞起来比较繁琐,有兴趣的可以自行查找资料。在这里并不推荐使用。

4.个人网站 或 社交软件中

现在中文世界, PGP的使用者中 有很多都是 独立的博客作者, 如果你拥有自己的博客或者个人网站,当然可以选择将自己的公钥发布在上面,最好给你的网站上一个Https 。

很多社交网站的个人展示页,可以自由编辑你的信息,你可以将PGP的 公钥发布在这里, 或者将 指纹 放在这, 这样通过其他渠道下载到公钥的人,也可以确认身份。

5. 代码仓库或Gist

无论你是不是开发者, 都可以拥有一个Github账号, 你可以开一个仓库专门用来发布自己的公钥,或者将公钥发布到Gist。

6. 共享笔记

Notion或者印象笔记等可以共享笔记的地方,都可以贴出你的公钥。

最后

使用分散的、多渠道的、可能是线下的方式来交换和确认公钥 ,不要相信在放一处的 公钥 和指纹。

去验证紧跟在公钥后面的指纹 , 就像你去问一个诈骗者,他是不是一个诈骗者一样无用。

如果不是当面,请至少从两个渠道进行验证,比如你从一个渠道(比如这里)得到了我的公钥 , 你想和我安全通信的话,导入前一定要从另一处(比如我公布的其他账号的简介)得到我的指纹, 验证是否一致后再进行操作。

而且每次使用前,请重复以上步骤,确保你手上的公钥是最新的。

参考链接

[1]. 用 PGP 保护代码完整性系列

[2]. The GNU Privacy Handbook

[3]. [GnuPG: 用多个sub keys保护primary key missing idea (wordpress.com)](https://jackqqcn.wordpress.com/2008/06/22/gnupg-用多个sub-keys保护primary-key/)

[4]. PGP 自我扫盲

[5]. GPG 的正确使用姿势

[6]. 电子邮件加密指南

[7]. Short key IDs are bad news (with OpenPGP and GNU Privacy Guard)

[8]. gnupg密钥签署原理和过程 // Shell’s Home (shell909090.org)

[9]. [PGP Key Server Roll Your Own Network](https://roll.urown.net/server/PGP-keyserver.html#a-public-key-shelf)

[10]. Are SKS keyservers safe? Do we need them?

[11]. SKS Keyserver Network Under Attack

[12]. OpenPGP 最佳实践 - 公钥服务器

[13]. GPG SKS 同步网络被投毒事件及其影响

[14]. where-to-upload-PGP-public-key-are-keyservers-still-surviving

[15]. GPG简明介绍


知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。