NSURLSession/NSURLConnection HTTP load Failed (kcfStreamErrorDomainSSL,-9802)
errorAn SSL error has occurred and a secure connection to the server cannot be made.@H_502_5@
我通过在我的info.plist中添加以下内容来修复它:@H_502_5@
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> <key>NSExceptionDomains</key> <dict> <key>xx.xx.xxx.xxx</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <key>NSIncludesSubdomains</key> <true/> <key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> </dict>
但是现在我正在连接到DIDFinishLoading代理方法中作为html响应:@H_502_5@
您的浏览器发送了此服务器无法理解的请求.@H_502_5@
我正在使用以下设置与服务器的信任:@H_502_5@
func connection(connection: NSURLConnection,canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool{ return true } func connection(connection: NSURLConnection,willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge){ print("willSendRequestForAuthenticationChallenge") let protectionSpace:NSURLProtectionSpace = challenge.protectionSpace let sender: NSURLAuthenticationChallengeSender? = challenge.sender if(protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust){ let trust:SecTrustRef = challenge.protectionSpace.serverTrust! let credential:NSURLCredential = NSURLCredential.init(forTrust: trust) sender?.useCredential(credential,forAuthenticationChallenge: challenge) } else{ sender?.performDefaultHandlingForAuthenticationChallenge!(challenge) } }
有人可以帮我找出问题吗?@H_502_5@
Hostname xx.xx.xxx.xx provided via SNI and hostname my_secured_host_name provided via HTTP are different@H_502_5@
UPDATE2:
由于服务已经是https,所以我已经从info.plist中删除了通过http的密钥@H_502_5@
UPDATE3:
当我尝试使用openssl as@H_502_5@
openssl s_client -showcerts -connect xx.xx.xxx.xxx:443@H_502_5@
CONNECTED(00000003) 8012:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:/SourceCache/OpenSSL098/OpenSSL098-52.40.1/src/ssl/s23_lib.c:185@H_502_5@
UPDATE4:
更改了Info.plist以执行以下操作:@H_502_5@
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>xx.xx.xxx.xxx</key> <dict> <key>NSExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/> </dict> </dict> </dict>
NSURLSession/NSURLConnection HTTP load Failed (kcfStreamErrorDomainSSL,-9802)
errorAn SSL error has occurred and a secure connection to the server cannot be made.@H_502_5@
问候
潘卡@H_502_5@
解决方法
以下参考可能是有用的(我从苹果的iOS开发库中逐字引用):
To override the hostname (to allow a certificate for one specific site
to work for another specific site,or to allow a certificate to work
when you connected to a host by its IP address),you must replace
the policy object that the trust policy uses to determine how to
interpret the certificate. To do this,first create a new TLS policy
object for the desired hostname. Then create an array containing that
policy. Finally,tell the trust object to use that array for future
evaluation of trust.@H_502_5@
SecTrustRef changeHostForTrust(SecTrustRef trust) { CFMutableArrayRef newTrustPolicies = CFArrayCreateMutable( kcfAllocatorDefault,&kcfTypeArrayCallBacks); SecPolicyRef sslPolicy = SecPolicyCreateSSL(true,CFSTR("www.example.com")); CFArrayAppendValue(newTrustPolicies,sslPolicy); #ifdef MAC_BACKWARDS_COMPATIBILITY /* This technique works in OS X (v10.5 and later) */ SecTrustSetPolicies(trust,newTrustPolicies); CFRelease(oldTrustPolicies); return trust; #else /* This technique works in iOS 2 and later,or OS X v10.7 and later */ CFMutableArrayRef certificates = CFArrayCreateMutable( kcfAllocatorDefault,&kcfTypeArrayCallBacks); /* Copy the certificates from the original trust object */ CFIndex count = SecTrustGetCertificateCount(trust); CFIndex i=0; for (i = 0; i < count; i++) { SecCertificateRef item = SecTrustGetCertificateAtIndex(trust,i); CFArrayAppendValue(certificates,item); } /* Create a new trust object */ SecTrustRef newtrust = NULL; if (SecTrustCreateWithCertificates(certificates,newTrustPolicies,&newtrust) != errSecSuccess) { /* Probably a good spot to log something. */ return NULL; } return newtrust; #endif }
资料来源:iOS Developer Library — Overriding TLS Chain Validation Correctly — Manipulating Trust Objects@H_502_5@
请注意,在同一页面上,您可以找到处理自签名SSL证书的其他代码段,以防您处理此类证书.@H_502_5@
要在Swift项目中使用此功能,请将新的C文件添加到您的项目(File .. New .. File .. iOS / Source / C_File),例如mysectrust.c和相应的头mysectrust.h(如果XCode要求你创建一个桥接头,说是)@H_502_5@
mysectrust.h@H_502_5@
#ifndef mysectrust_h #define mysectrust_h #include <Security/Security.h> SecTrustRef changeHostForTrust(SecTrustRef trust); #endif /* mysectrust_h */
mysectrust.c@H_502_5@
#include "mysectrust.h" SecTrustRef changeHostForTrust(SecTrustRef trust) { CFMutableArrayRef newTrustPolicies = CFArrayCreateMutable( kcfAllocatorDefault,&kcfTypeArrayCallBacks); SecPolicyRef sslPolicy = SecPolicyCreateSSL(true,CFSTR("www.example.com")); CFArrayAppendValue(newTrustPolicies,sslPolicy); #ifdef MAC_BACKWARDS_COMPATIBILITY /* This technique works in OS X (v10.5 and later) */ SecTrustSetPolicies(trust,newTrustPolicies); CFRelease(oldTrustPolicies); return trust; #else /* This technique works in iOS 2 and later,or OS X v10.7 and later */ CFMutableArrayRef certificates = CFArrayCreateMutable( kcfAllocatorDefault,&kcfTypeArrayCallBacks); /* Copy the certificates from the original trust object */ CFIndex count = SecTrustGetCertificateCount(trust); CFIndex i=0; for (i = 0; i < count; i++) { SecCertificateRef item = SecTrustGetCertificateAtIndex(trust,i); CFArrayAppendValue(certificates,item); } /* Create a new trust object */ SecTrustRef newtrust = NULL; if (SecTrustCreateWithCertificates(certificates,&newtrust) != errSecSuccess) { /* Probably a good spot to log something. */ return NULL; } return newtrust; #endif }
当然,请使用您的主机名替换上述代码中的www.example.com.@H_502_5@
然后,在Xcode项目projectname-Bridging-Header.h中找到桥接头,并附加以下行:@H_502_5@
#import "mysectrust.h"
现在你可以从Swift调用这个函数,例如:@H_502_5@
func whatever(trust: SecTrustRef){ let newTrust = changeHostForTrust(trust) // call to C function ... }