🔗 功能:模拟原始 SSL 服务器证书,用于拦截流量
- 目标:将原始 SSL 服务器证书信息传递给用户。允许用户就信任服务器证书做出明智的决定。
- 状态:已完成
- 版本: 3.3
- 开发者: AlexRousskov 和 Christos Tsantilas
- 更多:需要 bump-server-first,并受益于 动态 SSL 证书生成
🔗 动机
SslBump 的主要缺点之一是丢失了 SSL 服务器证书中嵌入的信息。从 Squid 的角度来看,有两种基本情况需要考虑。
- 有效的服务器证书: 用户可能仍然想知道原始服务器证书的颁发者、过期时间以及其他证书详细信息。在最坏的情况下,对于 Squid 而言有效的证书,可能无法通过 HTTPS 客户端测试,即使客户端信任 Squid 拦截连接。
- 无效的服务器证书: 这是一个特别糟糕的情况,因为它迫使 Squid 要么绕过证书验证错误(隐藏了对信任用户可能很关键的信息!),要么终止事务(不给用户一个做出知情例外选择的机会)。
隐藏原始证书信息从来不是合法 SslBump 部署的意图。相反,这是初始 SslBump 实现的一个不良副作用。幸运的是,在大多数情况下,可以消除这种限制,使 SslBump 的侵入性更小,危险性更低。
🔗 实现概述
OpenSSL API 允许我们在生成伪造服务器证书时提取并使用源服务器证书的属性。总的来说,我们希望模拟所有属性,但各种 SSL 规则使得模拟某些属性在技术上不可行,并且在某些条件下,浏览器行为使得模拟大多数属性不理想。我们将在下面详细介绍这些例外情况。Squid 管理员可以使用 sslproxy_cert_adapt 和 sslproxy_cert_sign 配置选项来调整模拟算法。
ssl_crtd 守护进程接收匹配的配置选项以及原始服务器证书,以模拟其属性。
需要 bump-server-first 支持,以便在将伪造证书发送给客户端之前获取原始服务器证书。
🔗 伪造证书属性
本节介绍了每个伪造证书属性的生成方式。“true”形容词用于描述从源服务器接收到的 SSL 证书的属性。“intended”形容词用于描述从客户端接收到的请求或连接的属性(包括拦截的连接)。
| x509 证书属性 | 拦截成功后 | 拦截失败后 |
|---|---|---|
| 通用名称 (CN) | 默认情况下为真实 CN。可以使用 sslproxy_cert_adapt setCommonName 进行覆盖。 | 如果 CONNECT 地址可用,则使用该地址,但需遵循下面单独讨论的 CN 长度控制。否则,如果真实 CN 可用,则使用真实 CN。如果这是拦截的连接且没有真实的 CN,则证书将没有 CN(也没有主题)。 |
| 别名 | 如果存在,则为真实别名。 | 无。 |
| 主题 | 默认情况下为真实主题。CN 部分可以覆盖(参见 CN)。 | 仅包含 CN(参见 CN)。 |
| 主题备用名称 (subjectAltName) | 默认情况下为真实名称(如果存在)。如果使用 sslproxy_cert_adapt setCommonName,则为无(浏览器会拒绝备用名称与 CN 无关的证书)。 | 无。 |
| 签名者和签名 | 默认情况下为配置的受信任 Squid CA。为了模拟“不受信任的真实服务器证书”错误,Squid 会生成一个不受信任的证书,其主题为受信任证书的主题,并加上“Untrusted by”字符串前缀(Squid 会根据需要用此不受信任的证书签名,但不会将其发送给用户,从而防止其被缓存)。为了模拟自签名证书错误,Squid 会生成一个自签名证书。 | 配置的受信任 Squid CA 证书。 |
| 颁发者 | 签名证书的主题(参见签名者)。 | |
| 序列号 | 签名证书和伪造证书属性的 20 字节 SHA1 哈希值。浏览器会拒绝具有相同颁发者、相同序列号但 CN 不同的证书。由于 Squid 必须为几乎所有 CN 使用相同的颁发者,因此我们必须确保即使在独立的 Squid 上生成时,如果 CN 不同,序列号也几乎绝不会相同。 | |
| 有效期 | 默认情况下为真实日期。如果真实有效期缺失或 sslproxy_cert_adapt setValidAfter 和 setValidBefore 处于活动状态,则使用签名证书的有效期。 | Squid 受信任证书的有效期。 |
| 版本 | 当模拟任何证书扩展(例如 subjectAltName)时(根据 RFC 5280),版本为 3。否则,OpenSSL 会设置版本(通常为 1?) | 由 OpenSSL 设置(通常为 1?) |
| 其他 | 未模拟或设置(参见局限性)。 |
Squid 生成的所有证书都使用配置的受信任 CA 证书私钥进行签名。这与序列号生成算法一起,使得独立的但配置相同的 Squid(包括但不限于 Squid SMP 工作进程)在类似情况下能够生成相同的证书。
🔗 延迟错误响应
当 Squid 无法与源服务器成功建立安全连接且启用了 bump-ssl-server-first 时,Squid 会记住错误页面,并在与客户端建立安全连接并接收到第一个加密客户端请求后才显示该错误页面。错误是安全显示的。对于通过 deny_info 配置的 Squid 重定向消息,也使用相同的方法。这种错误延迟的实现是由于 (a) 像 FireFox 和 Chromium 这样的浏览器无法正确显示 CONNECT 错误,以及 (b) 被拦截的 SSL 连接必须等待第一个请求才能显示错误。
此外,当 Squid 遇到错误时,它会使用一个具有最小属性的受信任证书来加密与客户端的连接。如果我们试图模拟真实的损坏证书,用户将看到一个浏览器错误对话框,然后,如果用户允许,将显示 Squid 的错误页面,其中包含关于问题的相同(甚至可能更详细/友好)的信息。使用受信任证书可以在许多情况下避免这种“双重错误”效果。而且,毕竟信息来自 Squid 而不是源服务器,所以在显示该信息时模拟损坏的源服务器详细信息有些不妥。
Squid 在显示错误后关闭客户端连接,以防止任何请求发送到损坏的服务器。
重要的是要理解,Squid 可以通过 sslproxy_cert_error 配置为忽略或容忍某些 SSL 连接建立错误。如果允许错误,Squid 将忽略该错误,模拟真实的损坏证书属性,并继续与服务器通信。否则,Squid 将不进行模拟并终止服务器连接,如上所述。因此,如果您希望用户看到损坏的证书属性而不是 Squid 的错误页面,您必须告知 Squid 忽略该错误。
🔗 长域名
RFC 5280 的 A.1 节将 SSL 证书的通用名称 (Common Name) 字段限制为 64 个字符。据我们所知,这意味着具有长名称的安全站点必须使用通配符证书。由于通配符不能应用于 TLD(例如,浏览器会拒绝 *.com 通配符),因此不存在具有长二级域名标签的安全站点。
如果 Squid 收到一个有效的真实证书,Squid 不会尝试强制执行 CN 长度限制,而是按照上面表格中的描述直接模拟真实证书字段。然而,当 Squid 无法连接到源服务器或无法接收到可用的真实证书时,Squid 必须从头开始生成一个最小的伪造证书,并且必须处理用户意图访问的站点的长域名。为了缩短名称,Squid 会尝试将较低级别的域名标签替换为通配符,直到 CN 长度不再超过 64 个字符的限制。如果该替换导致通配符是 TLD 通配符(如 *.com),或者更糟的是,是一个裸的 * 通配符,那么 Squid 将生成一个没有 CN 的证书。此类证书通常会被浏览器拒绝,并显示各种(通常具有误导性的)错误。例如:
| 请求中的长域名 | 用于显示 Squid 错误的证书 CN | 评论 |
|---|---|---|
| llanfairpwllgwyngyllgogerychwyrndrobwyll-llantysiliogogogoch.com | llanfairpwllgwyngyllgogerychwyrndrobwyll-llantysiliogogogoch.com | 该域名长度正好为 64 个字符,因此在 CN 限制范围内。 |
| www.llanfairpwllgwyngyllgogerychwyrndrobwyll-llantysiliogogogoch.com | 无。 | Squid 拒绝生成 *.com 通配符,并且将“www”替换为“*”会超出 64 个字符的限制 2 个字符。 |
| this-long-domain-exceeds-64-chars-but-should-not-crash-ssl-crtd.example.com | *.example.com | 浏览器将接受此通配符并显示 Squid 错误页面。 |
| www.this-long-domain-exceeds-64-chars-but-should-not-crash-ssl-crtd.example.com | *.example.com | 浏览器将拒绝此通配符,因为它们显然不允许通配符替换多个域名标签。 |
希望,过长的域名在安全站点中很少见。待办事项:找到一个实际有效的、具有长域名的公共安全站点。
🔗 使用 IP 地址的 URL
用户可能会在地址栏中输入 SSL 服务器的 IP 地址。一些浏览器(例如,Rekonq 浏览器 v0.7.x)即使在用户在地址栏中输入主机名时,也会在 CONNECT 请求中发送 IP 地址。目前,Squid 无法区分这两种情况,并假定 CONNECT 请求中的 IP 地址表示用户在地址栏中输入了该地址。除了假定用户输入外,Squid 在此处的总体行为旨在模仿 Squid 不在循环中会发生的情况。以下是当用户输入类似 https://74.125.65.99/ 而不是 https://www.google.com/ 的一些情况。
| Squid 配置 | 评论 | 浏览器显示 |
|---|---|---|
| 无 SslBump | 这是因为服务器证书未使用 IP 地址作为 CN。 | 浏览器内部的“服务器证书与 URL 不匹配”错误。 |
| SslBump 配合默认的 squid.conf | 这与无 SslBump 的行为匹配。但请参阅下表中的“始终 IP”。 | Squid 的 SQUID_X509_V_ERR_DOMAIN_MISMATCH 错误页面,使用从 CONNECT 请求中的 IP 地址设置的 CN 进行显示。 |
| sslproxy_cert_error allow all | 这是正确的行为,因为 Squid 被告知忽略错误,并且未被告知调整源服务器 CN。源服务器将 CN 设置为 www.google.com 或等效项,而浏览器期望的是 IP 地址。 | 浏览器内部的“服务器证书与 URL 不匹配”错误。 |
| sslproxy_cert_error allow all sslproxy_cert_adapt setCommonName ssl::certDomainMismatch | 因为 Squid 将伪造证书的 CN 设置为从 CONNECT 请求中的 IP 地址。但请参阅下方的“始终 IP”。 | Google 页面,无错误。 |
| sslproxy_cert_error allow all sslproxy_cert_adapt setCommonName{74.125.65.99} ssl::certDomainMismatch | Squid 将伪造证书的 CN 设置为从 CONNECT 请求中的 IP 地址。但请参阅下方的“始终 IP”。 | Google 页面,无错误。 |
始终 IP:带有此注释的配置可能无法与始终在 CONNECT 请求中使用 IP 地址的浏览器配合使用,因为它们的第二个请求 Host 头将与 CN IP 不匹配。在我们可以检测到此类浏览器发出的 CONNECT 请求之前,Squid 在这里无能为力。
🔗 IPv6
请求 URI 中的 IPv6 地址的处理方式如上所述。唯一与 IPv6 相关的注意事项是,当 Squid 需要根据 IP 地址形成证书 CN 字段时,它会去除周围的方括号。像 Firefox、Chromium 和 Safari 这样的浏览器更喜欢 CN 中的裸 IPv6 地址,即使 URL 中的 IPv6 地址带有方括号。当这些浏览器看到带有方括号的 CN 时,它们会产生令人困惑的错误。例如:
You attempted to reach [2001:470:1:18::120], but instead you actually reached
a server identifying itself as [2001:470:1:18::120]. Chromium can say for sure
that you reached [2001:470:1:18::120], but cannot verify that that is the same
site as [2001:470:1:18::120] which you intended to reach.
🔗 限制
某些浏览器(例如,Rekonq 浏览器 v0.7.x)即使在用户在地址栏中输入主机名时,也会在 CONNECT 请求中发送 IP 地址。Squid 无法同时处理这类浏览器和使用 IP 地址而不是主机名的 URL,因为 Squid 无法区分两种情况。在有人贡献代码来可靠地检测这些“不寻常”浏览器的 CONNECT 请求之前,我们对此无能为力。
SQUID_X509_V_ERR_DOMAIN_MISMATCH 错误直到客户端发送第一个加密请求后才进行检查。在处理拦截的连接或与不使用域名进行 CONNECT 请求的浏览器通信时,无法更早地检查这些错误。在处理包含预期域名信息的 CONNECT 请求时,可以检查这些错误,但 Squid 没有这样做。
证书链未被模拟。
🔗 未被模拟或设置的证书属性
并非所有真实的证书属性都会被模拟。最初,我们认为默认模拟所有属性是个好主意,但我们很快遇到了问题,浏览器会因为属性的组合不匹配或无效(例如,备用名称与 CN 不匹配)而拒绝伪造的证书。我们现在只模拟不太可能引起问题的属性。但是,仍有少数其他属性可能值得进一步研究以进行模拟:证书策略、主题目录属性、扩展密钥用法、最新 CRL 和主题信息访问。
如果通过 CA 证书配置,以下属性可能值得设置:颁发者密钥标识符、主题密钥标识符、密钥用法、颁发者备用名称、最新 CRL 和颁发者信息访问。
以下属性可能不适用,因为它们涉及 CA 或其他专业证书(或过于模糊而无法安全地模拟):基本约束、名称约束、策略约束和禁止任何策略。
类别:功能
导航:站点搜索,站点页面,类别,🔼 向上