“HTTPS 代理”这个说法只描述客户端与代理之间的传输,仅此而已。它并不表示后面的网站也由同一条连接加密,也不表示代理能读取页面。把这两条连接区分开之后,证书错误就不再神秘,与 VPN 的对比也变得具体。

两对端点,两次验证

在普通的隧道模式下,存在两条 TLS 关系。第一条从客户端连到代理,用于验证代理。第二条从客户端穿过隧道连到网站,用于验证网站。两者各自独立失败,也各自独立配置。

它们有各自的信任决策、各自的证书链和各自的错误信息。使用组织 CA 的代理与使用公共证书链的公共网站,本来就可能需要不同的验证配置,这并非配置错误。

把它们看成两条共用同一个套接字的连接,因为它们本来就是。

CONNECT 实际隧道化的是什么

客户端发送一个指明主机和端口的 CONNECT 请求,代理随即向该目标建立 TCP 连接。代理应答之后,后续字节被原样转发而不作解释,因此网站的 TLS 握手是原封不动地穿过代理的。于是代理只知道目标名称和连接元数据,在这种安排下它收不到解密后的页面。

这个区别正是隧道模式的全部安全论证,也是它的局限。

代理这一跳没有 TLS 的 HTTP 代理,依然可以通过 CONNECT 承载 HTTPS 网站。客户端与代理之间的交换是明文,而网站连接不是,把整件事叫作 HTTPS 代理恰好掩盖了这个差异。

是哪张证书失败了

验证失败时,先读错误里点名的那个端点,再去改任何信任设置。这两种失败在终端里看起来很像,指向的修复方法却完全不同,所以第一个问题永远是:哪条连接被拒绝了。

curl 正是为此把选项分开。代理 CA 文件配置的是对代理的验证,而 CA 文件配置的是对服务器的验证;适用哪种信任库行为还取决于 curl 的构建方式。

curl -v --proxy https://proxy.example.net:443 \
  --proxy-cacert org-ca.pem --cacert public-ca.pem https://www.example.com/

压制一项检查不是修复。它对任何一个端点都没有给出任何证明。

检查是另一种安排

TLS 检查不是隧道。做检查的中间人会终止面向网站的信任关系,并向客户端出示自己的证书,于是客户端验证的是中间人而不是网站。在经批准的设计下这可以是正当的,但它与逐字节转发是性质不同的主张。不要假定每个代理都会检查,也不要假定代理这一跳已加密就能排除它。

信任库里的组织 CA 只是提示你处于哪种安排,而不是证据。应当去问设计,而不是从证书链推断。

这两种安排对“谁能读取页面”这个问题的答案并不相同。

用同样的四行来比较代理和 VPN

只有把两种部署用同样的方式描述,这个比较才有用。

LineWhat to state
Protected segmentsWhich hops are encrypted, and between which endpoints
Verified identitiesWhat each end proves, and against which trust anchor
Trusted intermediariesWho can read or alter traffic by design
Traffic includedWhich processes and destinations the policy actually covers

为单个请求配置的代理只覆盖那个请求。它不会把设备上的每个进程都送进代理,示例命令正是这么窄。VPN 的覆盖范围取决于它的路由与应用策略,这同样需要查看而不是假定。两者都不会仅仅因为装上了就覆盖一切。

为每个选项写下这四行,争论通常就自行消解了。有用的比较不在于哪个标签听起来加密程度更高。它在于哪些区段受到保护、各自的端点验证了谁、你信任哪些中间人,以及策略实际覆盖了哪些流量。

相关文章