[iOS] 调试 SSL 握手失败

发布: (2026年1月11日 GMT+8 20:03)
5 min read
原文: Dev.to

Source: Dev.to

问题:意外的配置冲突

最近,我们的监控仪表板开始出现零星的网络错误日志。它们不是典型的 404 或 500,而是碎片化的低层错误,指向一个特定的罪魁祸首:SSL Handshake Failures

这出乎意料,因为我们的 ATS(App Transport Security)配置看起来是完全宽松的。我们在 Info.plist 中明确将 NSAllowsArbitraryLoads 设置为 true

NSAppTransportSecurity

    NSAllowsArbitraryLoads

理论上,这个设置应该绕过 ATS 检查,允许连接使用自签名证书或旧版 TLS 的服务器。然而,尽管有此配置,我们仍然看到持续的 TLS/SSL 网络错误。

在深入阅读文档后,我发现了 Apple 配置规则中的一个隐藏覆盖。

发现:InWebContent 覆盖

根本原因在于我们为 WebView 启用了另一个关键键:NSAllowsArbitraryLoadsInWebContent

我们启用了它以允许应用内浏览器加载混合内容。然而,Apple 文档中有一条关键说明:

“如果存在 NSAllowsArbitraryLoadsInWebContent,则 NSAllowsArbitraryLoads 的值会被覆盖为 NO。”

由于我们面向 iOS 10+,InWebContent 键的存在会悄悄地覆盖全局的 “Allow All” 设置。

  • 在 WebView 中: 任意加载被允许。
  • 本地网络(API 调用、图片加载): 全局标志被忽略,ATS 恢复为其 默认的严格模式

这导致我们的应用对所有 API 调用强制执行严格的 ATS 策略(TLS 1.2+,需要前向保密),即使我们本意是允许任意加载。

为什么 TLS 设置是嫌疑人

一旦明确严格的 ATS 已启用,“SSL Handshake Failure” 日志就变得合情合理。

  • 客户端(App): 强制使用 TLS 1.2 或更高(ATS 默认)。
  • 服务器端: 只能使用 TLS 1.0 的旧版服务器。

结果: 协商失败,连接被中断。

我们不经意间阻断了自己的旧版服务器,因为应用的安全标准在默认情况下被静默地设为最高。

误解:“不安全” ≠ “旧协议”

一种常见的解决办法是为有问题的域名启用 NSExceptionAllowsInsecureHTTPLoads。人们常误以为允许 “不安全加载” 会关闭所有检查,包括 TLS 版本要求。

这是错误的。

NSExceptionAllowsInsecureHTTPLoads 只允许对指定域名进行 HTTP(未加密)连接,但它 不会

  • 降低 TLS 版本要求(HTTPS 仍然需要 TLS 1.2)。
  • 绕过证书验证(自签名或已过期的证书仍会失败)。

如果服务器仅支持 TLS 1.0,握手仍会失败,无论此设置如何。

解决方案:精确配置

与其再次尝试强制全局 “Allow All”(这通常是不好的做法),我采用了精确的修复方式。

目标是:

  • 保持高安全性: 必须保持证书验证开启。
  • 降低兼容性障碍: 为特定的旧版域名显式允许旧协议。

以下是最终的 Info.plist 配置:

NSExceptionDomains

    legacy-api.example.com
    
        NSExceptionMinimumTLSVersion
        TLSv1.0
        NSExceptionRequiresForwardSecrecy
        
        NSIncludesSubdomains

此配置指示应用 严格检查证书,但 即使使用较旧的 TLS 1.0 协议也接受连接

部署与后续步骤

已部署更新的配置。如果假设正确,那些旧域名的 SSL/TLS 错误应该会消失。如果错误仍然存在,可能还有其他层面的原因——比如密码套件不匹配或中间证书问题。

我会在此帖子中更新结果。祈祷这就是这场 saga 的终点! 🤞

Summary

  • Watch out for overrides: NSAllowsArbitraryLoadsInWebContent silently disables NSAllowsArbitraryLoads.
  • Know your keys: NSExceptionAllowsInsecureHTTPLoads allows HTTP connections, but NSExceptionMinimumTLSVersion is required for TLS version issues.
  • Be specific: Don’t disable security globally. Configure exceptions only for the domains that actually need them.

参考文献

Back to Blog

相关文章

阅读更多 »

了解 SSL/TLS 证书

名称游戏:SSL 与 TLS SSL(Secure Sockets Layer)和 TLS(Transport Layer Security)常被交替使用,但 SSL 实际上已经死亡。它已经不再…

2026年如何成为 iOS 开发者

引言 在本文中,我将详细说明在2026年成为 iOS 开发者需要做些什么。本文面向两个群体:绝对初学者——那些没有…