NSURLSession/NSURLConnection HTTP load Failed (kcfStreamErrorDomainSSL,-9802)
errorAn SSL error has occurred and a secure connection to the server cannot be made.
<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响应:
400错误请求
错误的请求
您的浏览器发送了此服务器无法理解的请求.
我正在使用以下设置与服务器的信任:
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) } }
有人可以帮我找出问题吗?
Hostname xx.xx.xxx.xx provided via SNI and hostname my_secured_host_name provided via HTTP are different
如何在SNI中添加主机名?
UPDATE2:
由于服务已经是https,所以我已经从info.plist中删除了通过http的密钥
UPDATE3:
当我尝试使用openssl as
openssl s_client -showcerts -connect xx.xx.xxx.xxx:443
但我得到以下错误:
CONNECTED(00000003) 8012:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:/SourceCache/OpenSSL098/OpenSSL098-52.40.1/src/ssl/s23_lib.c:185
UPDATE4:
更改了Info.plist以执行以下操作:
<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.
问候
潘卡
解决方法
以下参考可能是有用的(我从苹果的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.
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
请注意,在同一页面上,您可以找到处理自签名SSL证书的其他代码段,以防您处理此类证书.
要在Swift项目中使用此功能,请将新的C文件添加到您的项目(File .. New .. File .. iOS / Source / C_File),例如mysectrust.c和相应的头mysectrust.h(如果XCode要求你创建一个桥接头,说是)
mysectrust.h
#ifndef mysectrust_h #define mysectrust_h #include <Security/Security.h> SecTrustRef changeHostForTrust(SecTrustRef trust); #endif /* mysectrust_h */
mysectrust.c
#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.
然后,在Xcode项目projectname-Bridging-Header.h中找到桥接头,并附加以下行:
#import "mysectrust.h"
func whatever(trust: SecTrustRef){ let newTrust = changeHostForTrust(trust) // call to C function ... }