手机和操作系统
NSURLErrorDomain -1200:iOS App 提示“发生了 SSL 错误”
NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."NSURLErrorDomain Code=-1200 的意思是:iOS 或 macOS 上的 App 无法建立安全连接,TLS 握手失败了。 苹果的 URL 加载系统会执行 App Transport Security(ATS),所以某些浏览器能打开的服务器,在 App 里照样可能失败。修法几乎都在服务器端,偶尔在 App 的 ATS 设置里。
先判断是网站的问题还是你设备的问题
所有用户都失败是服务器的问题,只有部分用户失败多半是网络或设备的问题。用 SSL 检测 查 App 访问的接口域名或网站:
curl ssl.sh/example.com
服务器不支持 TLS 1.2、套件太弱或证书链不完整,所有用户都会失败。服务器检测通过、只有部分用户失败,就看他们的网络和已安装的描述文件。在 Mac 上,用苹果的 ATS 诊断工具测试 App 实际访问的地址:
nscurl --ats-diagnostics --verbose https://api.example.com
原因
5 种原因里,前 3 种出在服务器的协议、证书或证书链上,后两种出在网络拦截和 App 的证书固定。
1. 服务器不满足 ATS 要求
ATS 要求 TLS 1.2 及以上和前向保密(ECDHE)套件。只提供 TLS 1.0/1.1 或 RSA 密钥交换的服务器会报 -1200。国内一些老旧的接口服务器、前面挂着老负载均衡的系统经常是这种情况。
2. 证书不符合苹果的规则
SHA-1 签名、RSA 密钥小于 2048 位、没有 SAN、有效期过长,都会让 ATS 或苹果的信任评估失败。看失败发生在哪一步,会报 -1200 或 -1202。
3. 证书链不完整或私有 CA
缺中间证书、或者私有 CA 的根证书没装,通常报 -1202,但有些握手路径会报 -1200。用 证书链工具 修好证书链。
4. 网络拦截
公司代理、需要认证的公共 Wi-Fi、VPN 或过滤类描述文件都可能破坏 TLS。用蜂窝数据测试。
5. 证书固定(Pinning)不匹配
App 固定了某张证书或公钥,服务器换了证书,App 自己的固定逻辑就会拒绝连接,常常表现为 -1200 或请求被取消(-999)。
在各浏览器/系统上的样子
同一个握手问题,App 日志里是 -1200,Safari 里是“无法建立安全连接”;证书不受信任时则改报 -1202。
| 场景 | 显示内容 |
|---|---|
| iOS / macOS App 日志 | NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." |
| 同一服务器在 Safari 里 | “Safari 无法建立安全连接” |
| App 里证书不受信任 | NSURLErrorDomain Code=-1202 |
| 安卓 App | Trust anchor for certification path not found 或 SSLHandshakeException |
站长怎么修
修法以服务器为主:开启 TLS 1.2 以上和 ECDHE 套件,使用公开证书和完整证书链;ATS 例外只作最后手段。
1. 让服务器达到 ATS 标准。
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_certificate /etc/nginx/ssl/api.example.com.fullchain.pem;
接口放在阿里云/腾讯云负载均衡或 API 网关后面的,在控制台把 TLS 安全策略调到最低 TLS 1.2。
2. 使用公开证书和完整证书链。 用 curl ssl.sh/example.com 检查。
3. 服务器实在改不了时,只针对那一个域名在 App 的 Info.plist 里加例外:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>legacy.example.com</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
4. 提前规划证书固定的轮换:固定多个公钥,并在服务器换证书之前发布新版 App。
常见问题
-1200 和 -1202 有什么区别?
-1200 是安全连接本身失败(协议、套件,或握手中收到致命告警);-1202 是握手已经走到收到证书这一步,但证书不受信任。-1202 指向证书或证书链,-1200 指向 TLS 设置或网络干扰。
直接把 NSAllowsArbitraryLoads 设成 YES 行不行?
不行。它会对所有连接关闭 ATS,降低 App 安全性,App 审核时还要说明理由。应该修服务器;服务器不归你管时,只给那一个域名加一条有针对性的例外。
只有部分用户的手机报错,为什么?
这些用户可能连着会拦截 TLS 的网络(公司 Wi-Fi、需要认证的公共 Wi-Fi),装了 VPN 或过滤类描述文件,或者 iOS 版本较老。从日志里取出底层的 _kCFStreamErrorCodeKey:比如 -9802 表示收到致命 TLS 告警,-9806 表示连接被关闭。