证书透明度致力于通过可审计的HTTPS提高互联网安全.

用一句话来说,证书透明度就是为HTTPS提供一个可审计,可追究责任的一种提高互联网安全的机制。

早在2016年谷歌就宣布从2017年10月起签发的证书都需要遵守其证书透明政策才能被浏览器信任,但2017年谷歌将强制性合规时间延迟到2018年4月。也就是说,在最新的Chrome中,你访问签发日期在2018年4月后的证书,凡是不在CT中的,Chrome将会标记器为不可信。

20180509更新: 据最新了解,谷歌将强制证书透明度期限挪至Chrome68。

在了解CT之前,我们先了解一下我们现在所处的互联网信任机制。

信任和责任

我们在互联网上的每一动作都需要一个基本的信任体系。当你通过浏览器去访问你的银行账户或你喜爱的社交媒体时,你肯定希望你访问的那个网站就是你在浏览器输入的那个网站。这种期望就基于一个基本的信任体系,这就是我们常听见的web PKI(Public Key Infrastructure)系统。

从一个较高的层次来看,PKI系统就像一个公证人,它通过签发数字证书来赋予服务器为网站提供服务的能力。这个数字证书就是我们常说的证书了,它包括了网站的域名,组织名称,有效期和一个公钥。对于每一个公钥来说,都有一个对应的私钥。如果服务器需要使用指定证书去为网站提供HTTPS服务,那么这个服务器就需要证明对该私钥的所有权。

网站获取数字证书的第三方机构就是CAs(Certificate Authorities). CAs在颁发证书前会验证操作者的域名所有权。如果一个数字证书是由一个浏览器信任的CA颁发的,那么该证书就可以用于HTTPS站点了。所有的这些验证都是浏览器内部实现的,给用户的唯一感知的只是浏览器上一个小绿锁🔐,或是出错时的一个错误。

PKI系统本身是很好的,但是作为一个信任系统,依然存在很多风险。一个最基本的风险就是,CA机构可以为任何网站颁发证书。这就意味着,Hong Kong Post Office可以为gmail.com或facebook.com签发证书,而且被大部分浏览器信任。更糟糕的是,如果CA被黑客攻击了,那么黑客可以在CA毫无知觉的情况下颁发任何证书,从而导致用户处于一个高风险的处境中。

如果某人控制了一个不属于他自己站点的证书,那么他可以模拟这个站点,从而窃取用户的信息。就目前来说,像火狐,苹果,谷歌都有他们自己的信任CA库。如果这些CA出现些问题,用户将承担很大的风险。

从中可看出,PKI少的就是责任追究机制。如果一个误颁发的证书只影响到个人,这中间没有任何反馈机制让其他人知道CA的失误行为。

这不是一个假想的状态。就在2011年,DigiNotar,一个荷兰的CA机构,被黑客攻陷。黑客利用该CA签发了一张*.google.com的证书,他们试图模拟Gmail,窃取伊朗用户的个人信息。

但这次攻击被Google探测到了,通过公钥固定技术(public key pinning)。公钥固定是一个有风险的技术,只有一些技术过硬的公司在使用。公钥固定所带来的风险往往超过其价值,它通常被认为是蹩脚机制的典型例子,被浏览器弃用。

如果公钥固定机制也不起作用了,那么我们怎么去探测CA的一些错误?这时CT就应运而生。CT的目标就是让所有的证书透明,这样误颁发的证书也能被发现,从而可以采取相应的应对措施。

CT的组成

如果所有的证明都透明化,那么误颁发的证书将暴露在公众视野中。CT通过区块链技术给PKI带来了一个责任追究机制。CT将可信的证书加入一个列表供每一个人审计。这听起来很简单,但考虑到互联网的分散性,建立一个可靠地责任追究机制还是有相当的挑战的。

CT系统是MPKI的一个延伸,它向MPKI中加入了新的参与者和角色。除浏览器和CA外,还引入了新的参与方,从而保证整个系统的健康状态。这几个方面是:

  • 日志操作员(Log operators)
  • 审计员 (Auditors)
  • 监控 (Monitors)

从某种意义上说,日志操作员是管理证书列表的人员,只有它才能往列表中添加证书。如果有人CT日志提交了一个浏览器信任的证书,日志操作员需要在最大合并延迟(MMD),一般24小时内将该证书合并到列表中。CT日志给提交者返回一张收据,也就是证书签名时间戳(SCT)。SCT证明了在宽限的期限内将证书包含在CT日志中。你可以通过CT API与CT日志交互(RFC 6962)。

审计员是一个保证日志操作员诚实的第三方机构。他们从互联网上的各个可用位置查询日志,并相互比对有关证书的内容。它们就像PKI的狗仔队一样。他们还通过测量SCT的时间戳和日志中显示的相应证书之间的时间来跟踪SCT是否准确。

监控是一种帮助提醒网站提示错误的服务。它会抓取日志以获取新证书,并在网站所有者发现新证书时提醒网站所有者。流行的监控包括SSLMate的CertSpotter和Facebook的证书透明度监控。 Cloudflare计划在年底前为客户提供集成到Cloudflare仪表板中的免费日志监控服务。

让浏览器感知证书已加入日志

推动网站采用CT的一种方式是浏览器开始要求网站的证书被CT日子记录。通过在建立连接时直接查询CT日志来验证证书是否存已经加入日志的方式在潜在的隐私问题(将浏览器历史暴露给第三方),而且增加了延迟。相反,确保证书已加入日志的更好方法是要求服务器提供SCT,即上一节中介绍的日志返回的收据。

SCT可以通过多种方式呈现给客户端。最常用的方法是在签发证书时将SCT嵌入到证书中。这涉及CA在证书最终确定之前向各种CT日志提交预证书(证书的前体)以获取SCT。

对于没有嵌入SCT的证书,服务器有其他机制可将SCT传输到客户端。 SCT可以作为TLS扩展或作为OCSP响应包含在连接中。这些机制更难以可靠地执行,但它们允许任何证书被包含在CT中。

A certificate with embedded SCTs

CT的浏览器支持

并非所有日志都是平等创建的。恶意CA可能会与一组日志共同创建一个证书和一组SCT,而不会将证书合并到日志中。这个证书可以被用来攻击用户。为了保护生态系统免遭这种串通风险,支持CT的浏览器只选择主动接受审核的日志列表中的SCT。除此之外,还有多样性要求:日志应由不同基础设施上的不同实体进行管理,以避免串通或日志服务中断。如果连接从审查日志向客户端提供了足够多的SCT以符合证书的风险特征,则连接被认为是“CT合格”。

为了使连接在Chrome中符合CT条件,那就必须遵循Chrome的CT政策。对于大多数证书而言,这意味着至少需要为Chrome提供一个Google或一个非Google但被Chrome信任的日志才能显示SCT。有效期较长的证书必须有超过两个SCT。

为了成为受Chrome的信任的CT日志服务,CT日志服务需要向Chrome提交,并通过长达90天的监控期。在此期间,必须通过一些严格的要求。其中包括:

  • 没有超过超过24小时的MMD(最大合并延迟)的中断
  • 有99%的正常运行时间,没有停机时间超过最大合并延迟时间(由Google测量)
  • 在最大合并延迟的时间内将日志中已签发SCT加入日志列表
  • 通过始终提供Merkle树的一致视图保持Log的只添加属性

完整的政策在这里这里有完整的审查日志列表。

All or nothing

CT只有在所有证书都记录在可信的日志中时才真正的确保用户的安全。如果CA颁发的证书被浏览器信任,但未提交到CT日志中,则用户仍然可能受到有针对性的攻击。

在过去的几年中,Chrome已经要求所有的EV证书都符合CT标准。这还不够。只要存在浏览器信任但未提交到CT的证书,用户就会面临风险。这就是为什么Chrome团队宣布他们将在2018年4月开始要求所有新颁发的,公开信任的证书支持证书透明。

CA的改变

在浏览器中展示时,确保证书始终是符合CT政策的最安全方法是向足够的CT日志提交而获得足够的SCT从而保证符合浏览器的策略。但这对于一些CA来说,在操作上,这是一个很大改变,因为

  • 它增加了必须了解不同浏览器的CT策略需要哪些SCT并跟上策略变化的额外步骤
  • 它在颁发过程中添加了一个步骤,在该过程中将证书颁发前的预证书(pre-certificates)提交到不同的日志
  • 一些CT日志可能有中断或响应速度缓慢,因此可能需要回退策略才能避免延迟发布

建立一个可验证的全球一致的日志

PKI体系是巨大的。业界对HTTPS的推动已经向Web PKI引入了数百万个新证书。 CT中记录了超过25亿个证书!这个数字每天增长将近一百万。随着接Chrome的四月份期限到来,这个数字肯定还会增长。管理一个如此大的只添加、高可用的数据库是一项重大的工程挑战。

用于只增数据库的天然数据结构是哈希链。在哈希链中,元素按顺序对齐并使用SHA-256等单向哈希函数进行组合。下图描述了如何从值列表d1到d8创建哈希链。从第一个元素d1开始,d1的哈希值为a,然后变成链的头部。每当元素被添加到链中时,从当前链头和新元素计算出新的散列值。这个散列值成为新的链头。因为单向哈希函数不能被逆转,所以不可能在不改变整个链的情况下改变一个值。这使得哈希链的历史记录非常难以篡改。

哈希链是插入新元素的最佳数据结构:每个新增的元素只需计算一个哈希值。 然而,在验证元素是否正确的加入给定的了链头中,它的效率不是很理想。 在下面的例子中,你需要六个额外的元素(b,d4-d8)才能验证d3在8个值的链上是正确的。 你平均需要大约n / 2个元素才能验证长度为n的链中的元素。 在计算机科学方面,这被称为“线性缩放”。

在构建系统时,最好尽量降低参与者的复杂度。对于CT,我们主要关心的参与者是日志操作员和审核员。如果我们选择一个散列链作为我们的数据结构,日志操作员的工作将很容易,但审核员的工作将非常困难。我们可以做得更好。

当你问一位科学家如何优化算法时,十次有九次,他们建议的解决方案是使用一棵树(另外1/10次,他们会建议布隆过滤器)。这正是我们在这里所能做的。具体来说,我们可以使用一个名为Merkle树的数据结构。它就像一个哈希链,但不是在一行中散列元素,而是成对哈希。

对于每个新元素,不是将其散列加入总树中,而是将元素排列到平衡二叉树中,并计算该元素与其兄弟的散列。这里给你一半的值,将这些值得散列成对排列创建数的下一层,然后继续,直到你得到一个元素,树的顶部也就是树头。向Merkle树添加一个新值需要修改树中每层最多一个散列,也就是从这个元素到树头路径上的散列。

二叉树的深度相对于元素的数量是对数的。 粗略地说,如果树大小为8 = 2 ^ 3,则深度为4(= 3 + 1),如果是1024 = 2 ^ 10,则树深度为11(= 10 + 1),对于1048576 = 2 ^ 20树的大小是21(= 20 + 1)。 插入的代价至多是log_2(size),这比散列链中的差,但通常不会太糟糕。

使Merkle树如此有用的主要原因是它的验证效率。 不需要像在散列链中那样计算n / 2散列,只需要树中将元素引导到根的元素值即可, 这被称为共路径。 下图为d3计算共同路径。

copath包含树的每个级别的一个值。 因此,证明一个元素是正确的(包含证明)所需的计算是对数的,而不是像散列树那样的线性。 相对而言树的插入和验证都很高效,这使得Merkle树成为CT的理想数据结构。

证书透明日志也就是图中叶子元素是证书的Merkle树。 每个日志都有一个私钥,用于定期为当前树头签名。 一些CT日志非常庞大,有超过一亿的条目,但由于Merkle树的效率,包含证明只需要大约30次哈希。 这种结构在日志操作员向日志中添加证书时的成本与审计员验证其一致性的成本之间提供了良好的平衡。