kCFStreamErrorDomainSSL -9802 错误,但它是 HTTPS URL
kCFStreamErrorDomainSSL -9802 error but it's HTTPS URL
所以我知道 ATS 的东西以及如何编辑 info.plist 以允许 HTTP。但是,URL 是 https://api.map.baidu.com/api?v=2。 0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1,这是一个 HTTPS 请求,但我仍然得到
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
然后我在didFinishLaunchingWithOptions
中添加setenv("CFNETWORK_DIAGNOSTICS", "3", 1);
以启用详细日志。
在日志中,我找到错误日志:
5510 Jan 14 10:52:01 MCompass[8549] <Notice>: CFNetwork Diagnostics [3:363] 10:52:01.458 {
5511 Response Error
5512 Request: <CFURLRequest 0x7fecf3cddcb0 [0x10aff37b0]> {url = https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1, cs = 0x0}
5513 Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fecf406bbf0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7fecf406cda0 [0x10aff37b0]>{type = immutable, count = 3, values = (
5514 0 : <cert(0x7fecf3fa80e0) s: baidu.com i: VeriSign Class 3 International Server CA - G3>
5515 1 : <cert(0x7fecf3fa8920) s: VeriSign Class 3 International Server CA - G3 i: VeriSign Class 3 Public Primary Certification Authority - G5>
5516 2 : <cert(0x7fecf4069fd0) s: VeriSign Class 3 Public Primary Certification Authority - G5 i: Class 3 Public Primary Certification Authority>
5517 )}}
5518 } [3:363]
5519 Jan 14 10:52:01 MCompass[8549] <Notice>: CFNetwork Diagnostics [3:364] 10:52:01.459 {
5520 Did Fail
5521 Loader: <CFMutableURLRequest 0x7fecf3cdd9f0 [0x10aff37b0]> {url = https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1, cs = 0x0}
5522 Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fecf406bbf0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7fecf406cda0 [0x10aff37b0]>{type = immutable, count = 3, values = (
5523 0 : <cert(0x7fecf3fa80e0) s: baidu.com i: VeriSign Class 3 International Server CA - G3>
5524 1 : <cert(0x7fecf3fa8920) s: VeriSign Class 3 International Server CA - G3 i: VeriSign Class 3 Public Primary Certification Authority - G5>
5525 2 : <cert(0x7fecf4069fd0) s: VeriSign Class 3 Public Primary Certification Authority - G5 i: Class 3 Public Primary Certification Authority>
5526 )}}
5527 init to origin load: 0.00280595s
5528 total time: 0.447458s
5529 total bytes: 0
5530 } [3:364]
我很困惑,因为它是 HTTPS 请求,但仍然有问题。我在 Chrome 上尝试了 URL,它是 return 一个有效的证书(我有像 X509 这样的证书知识)。但是想不通为什么会被屏蔽
有人可以帮忙吗?预先感谢。将此域添加到 ATS 例外中会有所帮助,但我不想添加它,因为它已经是 HTTPS 了!
更新:
运行
/usr/bin/nscurl --ats-diagnostics -v "https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1"
将return全部通过:
Xuans-MacBook-Pro:~ xuan$ /usr/bin/nscurl --ats-diagnostics -v "https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1"
Starting ATS Diagnostics
Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1.
A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error.
================================================================================
Default ATS Secure Connection
---
ATS Default Connection
ATS Dictionary:
{
}
Result : PASS
---
================================================================================
Allowing Arbitrary Loads
---
Allow All Loads
ATS Dictionary:
{
NSAllowsArbitraryLoads = true;
}
Result : PASS
---
================================================================================
Configuring TLS exceptions for api.map.baidu.com
---
TLSv1.2
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.2";
};
};
}
Result : PASS
---
---
TLSv1.1
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.1";
};
};
}
Result : PASS
---
---
TLSv1.0
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.0";
};
};
}
Result : PASS
---
================================================================================
Configuring PFS exceptions for api.map.baidu.com
---
Disabling Perfect Forward Secrecy
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
Configuring PFS exceptions and allowing insecure HTTP for api.map.baidu.com
---
Disabling Perfect Forward Secrecy and Allowing Insecure HTTP
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
Configuring TLS exceptions with PFS disabled for api.map.baidu.com
---
TLSv1.2 with PFS disabled
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.2";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.1 with PFS disabled
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.1";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.0 with PFS disabled
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.0";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for api.map.baidu.com
---
TLSv1.2 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionMinimumTLSVersion = "TLSv1.2";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.1 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionMinimumTLSVersion = "TLSv1.1";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.0 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionMinimumTLSVersion = "TLSv1.0";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
正如在 上讨论的那样,仅通过 HTTPS 访问您的 API url 并不意味着它将符合 Apple 的 ATS。我也用nscurl
,但我认为这个工具还不够成熟,有时可能效率很低。
SSL Labs 测试要好得多,而且 详细 ,恕我直言。它将帮助您找出 SSL 配置中缺少的内容。
请注意 ATS requires TLS 1.2 和完美前向保密密码套件。
我不知道这是否能解决您的问题,但我最近遇到了类似的问题。在我的例子中,我也有一台服务器通过了 nscurl --ats-diagnostics
,每个服务器都通过了 PASS,但由于应用程序中的 ATS -9802 错误而失败。服务器使用 TLS 1.2 版,具有前向保密性,使用良好的密码套件,并具有 SHA256 证书。
SSL Labs 页面有指向答案的提示 -- 它说一切都很好,但 SSL 链不完整。服务器配置略有错误,因为它提供了正确的证书,但没有提供连接到根证书(应该已经在客户端上)所需的中间证书。有指向可以下载中间证书的位置的指针,因此 SSL Labs 页面这样做了,结果只是将等级降级为 "B"。但是,这意味着客户端实现还需要能够自行下载中间证书——并非所有实现都如此。
在我的例子中,因为这是在 testing/development 环境中,我们遇到其他服务器偶尔配置错误的问题,所以我们将 AFSecurityPolicy 属性 validatesDomainName
设置为 NO,因为解决了这些其他问题(在生产中当然是 YES)。但是,这也成为了这个服务器的设置,这并不是绝对必要的。这反过来意味着 AFSecurityPolicy 在配置 SecTrustRef
时使用 SecPolicyCreateBasicX509()
而不是 SecPolicyCreateSSL()
。这基本上没问题,除了 SecTrustGetNetworkFetchAllowed()
的 header 文档指出:
By default, network fetch of missing certificates is enabled if
the trust evaluation includes the SSL policy, otherwise it is disabled.
所以,这就是问题所在。 nscurl
将使用 SSL 策略,因此它会下载中间证书并正常工作。但是,随着该标志被关闭,ATS 将在运行时失败,因为 SecTrustEvaluate()
将 return kSecTrustResultRecoverableTrustFailure
,如果没有进一步的干预将被视为失败。如果我将 validatesDomainName
设置回 YES,它就会开始工作(在此服务器上)。或者,如果在将策略添加到 SecTrustRef 后您有一个句柄,您可以调用
SecTrustSetNetworkFetchAllowed(trustRef, true);
因为即使使用 X509 策略,这也将允许 App Transport Security 获取中间证书。或者,您可以修复服务器配置以提供整个证书链,但不包括根证书,就像它应该的那样。
编辑: SecTrustSetNetworkFetchAllowed
调用仅适用于 iOS10。对于 iOS9,我必须使用 SSL 策略调用 SecTrustSetPolicies()
,即重置策略列表——这是 ATS 在 iOS9 上获取丢失证书的唯一方法。
所以我知道 ATS 的东西以及如何编辑 info.plist 以允许 HTTP。但是,URL 是 https://api.map.baidu.com/api?v=2。 0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1,这是一个 HTTPS 请求,但我仍然得到
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
然后我在didFinishLaunchingWithOptions
中添加setenv("CFNETWORK_DIAGNOSTICS", "3", 1);
以启用详细日志。
在日志中,我找到错误日志:
5510 Jan 14 10:52:01 MCompass[8549] <Notice>: CFNetwork Diagnostics [3:363] 10:52:01.458 {
5511 Response Error
5512 Request: <CFURLRequest 0x7fecf3cddcb0 [0x10aff37b0]> {url = https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1, cs = 0x0}
5513 Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fecf406bbf0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7fecf406cda0 [0x10aff37b0]>{type = immutable, count = 3, values = (
5514 0 : <cert(0x7fecf3fa80e0) s: baidu.com i: VeriSign Class 3 International Server CA - G3>
5515 1 : <cert(0x7fecf3fa8920) s: VeriSign Class 3 International Server CA - G3 i: VeriSign Class 3 Public Primary Certification Authority - G5>
5516 2 : <cert(0x7fecf4069fd0) s: VeriSign Class 3 Public Primary Certification Authority - G5 i: Class 3 Public Primary Certification Authority>
5517 )}}
5518 } [3:363]
5519 Jan 14 10:52:01 MCompass[8549] <Notice>: CFNetwork Diagnostics [3:364] 10:52:01.459 {
5520 Did Fail
5521 Loader: <CFMutableURLRequest 0x7fecf3cdd9f0 [0x10aff37b0]> {url = https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1, cs = 0x0}
5522 Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fecf406bbf0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7fecf406cda0 [0x10aff37b0]>{type = immutable, count = 3, values = (
5523 0 : <cert(0x7fecf3fa80e0) s: baidu.com i: VeriSign Class 3 International Server CA - G3>
5524 1 : <cert(0x7fecf3fa8920) s: VeriSign Class 3 International Server CA - G3 i: VeriSign Class 3 Public Primary Certification Authority - G5>
5525 2 : <cert(0x7fecf4069fd0) s: VeriSign Class 3 Public Primary Certification Authority - G5 i: Class 3 Public Primary Certification Authority>
5526 )}}
5527 init to origin load: 0.00280595s
5528 total time: 0.447458s
5529 total bytes: 0
5530 } [3:364]
我很困惑,因为它是 HTTPS 请求,但仍然有问题。我在 Chrome 上尝试了 URL,它是 return 一个有效的证书(我有像 X509 这样的证书知识)。但是想不通为什么会被屏蔽
有人可以帮忙吗?预先感谢。将此域添加到 ATS 例外中会有所帮助,但我不想添加它,因为它已经是 HTTPS 了!
更新:
运行
/usr/bin/nscurl --ats-diagnostics -v "https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1"
将return全部通过:
Xuans-MacBook-Pro:~ xuan$ /usr/bin/nscurl --ats-diagnostics -v "https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1"
Starting ATS Diagnostics
Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ&s=1.
A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error.
================================================================================
Default ATS Secure Connection
---
ATS Default Connection
ATS Dictionary:
{
}
Result : PASS
---
================================================================================
Allowing Arbitrary Loads
---
Allow All Loads
ATS Dictionary:
{
NSAllowsArbitraryLoads = true;
}
Result : PASS
---
================================================================================
Configuring TLS exceptions for api.map.baidu.com
---
TLSv1.2
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.2";
};
};
}
Result : PASS
---
---
TLSv1.1
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.1";
};
};
}
Result : PASS
---
---
TLSv1.0
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.0";
};
};
}
Result : PASS
---
================================================================================
Configuring PFS exceptions for api.map.baidu.com
---
Disabling Perfect Forward Secrecy
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
Configuring PFS exceptions and allowing insecure HTTP for api.map.baidu.com
---
Disabling Perfect Forward Secrecy and Allowing Insecure HTTP
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
Configuring TLS exceptions with PFS disabled for api.map.baidu.com
---
TLSv1.2 with PFS disabled
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.2";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.1 with PFS disabled
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.1";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.0 with PFS disabled
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionMinimumTLSVersion = "TLSv1.0";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for api.map.baidu.com
---
TLSv1.2 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionMinimumTLSVersion = "TLSv1.2";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.1 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionMinimumTLSVersion = "TLSv1.1";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
---
TLSv1.0 with PFS disabled and insecure HTTP allowed
ATS Dictionary:
{
NSExceptionDomains = {
"api.map.baidu.com" = {
NSExceptionAllowsInsecureHTTPLoads = true;
NSExceptionMinimumTLSVersion = "TLSv1.0";
NSExceptionRequiresForwardSecrecy = false;
};
};
}
Result : PASS
---
================================================================================
正如在 nscurl
,但我认为这个工具还不够成熟,有时可能效率很低。
SSL Labs 测试要好得多,而且 详细 ,恕我直言。它将帮助您找出 SSL 配置中缺少的内容。
请注意 ATS requires TLS 1.2 和完美前向保密密码套件。
我不知道这是否能解决您的问题,但我最近遇到了类似的问题。在我的例子中,我也有一台服务器通过了 nscurl --ats-diagnostics
,每个服务器都通过了 PASS,但由于应用程序中的 ATS -9802 错误而失败。服务器使用 TLS 1.2 版,具有前向保密性,使用良好的密码套件,并具有 SHA256 证书。
SSL Labs 页面有指向答案的提示 -- 它说一切都很好,但 SSL 链不完整。服务器配置略有错误,因为它提供了正确的证书,但没有提供连接到根证书(应该已经在客户端上)所需的中间证书。有指向可以下载中间证书的位置的指针,因此 SSL Labs 页面这样做了,结果只是将等级降级为 "B"。但是,这意味着客户端实现还需要能够自行下载中间证书——并非所有实现都如此。
在我的例子中,因为这是在 testing/development 环境中,我们遇到其他服务器偶尔配置错误的问题,所以我们将 AFSecurityPolicy 属性 validatesDomainName
设置为 NO,因为解决了这些其他问题(在生产中当然是 YES)。但是,这也成为了这个服务器的设置,这并不是绝对必要的。这反过来意味着 AFSecurityPolicy 在配置 SecTrustRef
时使用 SecPolicyCreateBasicX509()
而不是 SecPolicyCreateSSL()
。这基本上没问题,除了 SecTrustGetNetworkFetchAllowed()
的 header 文档指出:
By default, network fetch of missing certificates is enabled if the trust evaluation includes the SSL policy, otherwise it is disabled.
所以,这就是问题所在。 nscurl
将使用 SSL 策略,因此它会下载中间证书并正常工作。但是,随着该标志被关闭,ATS 将在运行时失败,因为 SecTrustEvaluate()
将 return kSecTrustResultRecoverableTrustFailure
,如果没有进一步的干预将被视为失败。如果我将 validatesDomainName
设置回 YES,它就会开始工作(在此服务器上)。或者,如果在将策略添加到 SecTrustRef 后您有一个句柄,您可以调用
SecTrustSetNetworkFetchAllowed(trustRef, true);
因为即使使用 X509 策略,这也将允许 App Transport Security 获取中间证书。或者,您可以修复服务器配置以提供整个证书链,但不包括根证书,就像它应该的那样。
编辑: SecTrustSetNetworkFetchAllowed
调用仅适用于 iOS10。对于 iOS9,我必须使用 SSL 策略调用 SecTrustSetPolicies()
,即重置策略列表——这是 ATS 在 iOS9 上获取丢失证书的唯一方法。