两个人看同一个 SSTP 部署,可能得出相反的结论。一个读产品文档,看到 SSL 三个字母,就认定隧道跑的是多年前已停用的协议。另一个指着现代的握手过程,认为问题已经了结。两人争论的都是标签,而不是协商出来的版本,而只有后者才算证据。真正值得做的比较,是名字所承诺的,与服务实际选择的。

同一个问题的两种答案

标签式论点很好说:SSTP 被描述为安全套接字隧道协议,历史上的名字里有 SSL,所以连接必定是 SSL 3.0。它之所以流传,是因为这个名字确实来自那条脉络,也因为重复它的人大多从未看过一次握手。它还能流传,是因为这个结论听起来很保守,仿佛把最坏情况当默认就是稳妥选择。假设最坏情况与测量真实版本是两件事,只有一件能改变什么。

证据式论点问的是更窄的问题。此时此刻、在这个端点上,这个客户端和这个服务端究竟协商了哪个协议版本?答案来自终接 TLS 的那个服务,而不是来自宣传页,也不是来自打开了同名网站的浏览器。

两种论点的差别在于能证明什么。标签无法区分旧部署与已修补的部署,握手也说不清同一主机上无关服务在做什么。用后者,别再使用前者。

读取服务实际选择的版本

先把组件点名:客户端实现、服务端实现、TLS 端点,以及两者之间任何终止并重建 TLS 的设备。一个终止 TLS、再以明文 HTTP 与后端通信的负载均衡器,会改变你需要阅读哪台设备的策略。

openssl s_client -connect vpn.example.com:443 -servername vpn.example.com </dev/null> | grep -E 'Protocol|Cipher'
Get-WinEvent -LogName System -ProviderName Schannel -MaxEvents 20

把端点与时间同结果一起记录,因为日后策略变更会让没有日期的观察变得毫无价值。从与你关心的用户处于同一网络路径的客户端重复探测,因为中间拦截设备可能用自己的设置终止 TLS。如果两个位置结论不一致,你就找到了关键的组件。如果一致,你手里是证据而不是口号。

把记录字段与协商结果分开

某个字段里看起来古老的版本号,与真正的 SSL 3.0 会话不是同一件事。RFC 7568 把记录层版本与协商协议视为两个不同的问题,而自信的错误答案恰恰来自这里。先读协商协议,再读加密套件,然后才对会话下结论。

同一份文件对协议本身毫不含糊:不得使用 SSL 3.0,禁止协商或回退到它。理由是 POODLE 攻击所利用的破损 CBC 结构,这是协议本身的属性,而非某个应用的配置。

所以“这个负载大概很难被利用”不能成为继续启用 SSL 3.0 的理由。要求是移除该协议,而不是赢下一场关于单次演示的争论。

用站得住脚的策略让 SSL 3.0 退役

在 Windows 上,Schannel 的协议设置位于 Protocols 键之下,并分别按客户端与服务端角色读取,因此修好一个方向可能留下另一个方向未动。当前设置及其重启要求由 Microsoft 记录在案,而同主机上的第三方 TLS 库完全不会理会它们。

Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server'
Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols'

通过受支持的管理路径修改策略,确认属主服务重新读取了配置,并保留一条获批的回退方式。把别处环境里的大范围注册表脚本直接粘过来,正是把单个服务的修复变成整台机器所有 TLS 客户端中断的方式。重启范围在这里很重要:看起来已生效的设置,可能仍被尚未重新加载它的服务保存在内存里。

仍要求旧版本的对接方需要升级或迁移计划。未记录在案的例外、悄悄恢复旧协议,不是兼容策略,也过不了下一次审计。

用新连接验收改动

改完策略后要用新会话测试,因为在改动之前建立的连接,无法证明现在生效的配置。确认被允许的协议成功、被禁止的协议在获授权的验证流程中失败,然后让证书身份与信任校验保持原样。

记住握手并不覆盖的部分。SSTP 在 TLS 层之后承载 PPP 认证,因此现代协议版本并不能说明哪个用户获得了授权,也不能说明会话能访问哪些资源。那是另一套控制,需要另一套证据。

把结果写成:服务、后端、允许的策略、观察到的版本。这样的记录才能精确回答安全问题,而标签式论点与嫌麻烦的论点都做不到。

相关文章