pan*_*kaj 15 https ios swift tls1.2
我正在尝试访问https协议上提供的Web服务.最初我收到以下错误:
NSURLSession/NSURLConnection HTTP加载失败(kCFStreamErrorDomainSSL,-9802)errorAn发生SSL错误,无法建立与服务器的安全连接.
我通过在info.plist中添加以下内容来修复它:
<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>
Run Code Online (Sandbox Code Playgroud)
但是现在我在connectionDidFinishLoading委托方法中得到以下html作为响应:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
我正在使用以下来与服务器建立信任:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
服务器日志显示以下错误:
通过SNI提供的主机名xx.xx.xxx.xx和通过HTTP提供的主机名my_secured_host_name是不同的
如何在SNI中添加主机名?
我已经从info.plist中删除了密钥,因为该服务已经是https
当我尝试使用openssl时
openssl s_client -showcerts -connect xx.xx.xxx.xxx:443
但我得到以下错误:
CONNECTED(00000003)8012:错误:140790E5:SSL例程:SSL23_WRITE:ssl握手失败:/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>
Run Code Online (Sandbox Code Playgroud)
仍然有以下错误:
NSURLSession/NSURLConnection HTTP加载失败(kCFStreamErrorDomainSSL,-9802)errorAn发生SSL错误,无法建立与服务器的安全连接.
除了其他答案和评论中已经解决的 ATS 问题之外,您似乎正在尝试通过其 IP 地址连接到 SSL 服务器。\n以下参考可能有用(我逐字引用Apple 的 iOS 开发者库):
\n\n\n\n\n要覆盖主机名(允许一个特定站点的证书适用于另一个特定站点,或者允许证书在您通过 IP 地址连接到主机时起作用),您必须替换该策略信任策略用于确定如何解释证书的对象。为此,请首先为所需主机名创建一个新的 TLS 策略对象。然后创建一个包含该策略的数组。\n 最后,告诉信任对象使用该数组来评估未来的信任。
\n
SecTrustRef changeHostForTrust(SecTrustRef trust)\n{\n CFMutableArrayRef newTrustPolicies = CFArrayCreateMutable(\n kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);\n\n SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.example.com"));\n\n CFArrayAppendValue(newTrustPolicies, sslPolicy);\n\n#ifdef MAC_BACKWARDS_COMPATIBILITY\n /* This technique works in OS X (v10.5 and later) */\n\n SecTrustSetPolicies(trust, newTrustPolicies);\n CFRelease(oldTrustPolicies);\n\n return trust;\n#else\n /* This technique works in iOS 2 and later, or\n OS X v10.7 and later */\n\n CFMutableArrayRef certificates = CFArrayCreateMutable(\n kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);\n\n /* Copy the certificates from the original trust object */\n CFIndex count = SecTrustGetCertificateCount(trust);\n CFIndex i=0;\n for (i = 0; i < count; i++) {\n SecCertificateRef item = SecTrustGetCertificateAtIndex(trust, i);\n CFArrayAppendValue(certificates, item);\n }\n\n /* Create a new trust object */\n SecTrustRef newtrust = NULL;\n if (SecTrustCreateWithCertificates(certificates, newTrustPolicies, &newtrust) != errSecSuccess) {\n /* Probably a good spot to log something. */\n\n return NULL;\n }\n\n return newtrust;\n#endif\n}\nRun Code Online (Sandbox Code Playgroud)\n\n来源:iOS 开发者库 \xe2\x80\x94 正确覆盖 TLS 链验证 \xe2\x80\x94 操作信任对象
\n\n请注意,在同一页面上,您可以找到另一个处理自签名 SSL 证书的代码片段(如果您正在处理此类证书)。
\n\n要在 Swift 项目中使用此函数,请向您的项目添加一个新的C 文件(File.. New.. File.. iOS/Source/C_File),例如mysectrust.c以及相应的标头mysectrust.h(如果 XCode 要求您创建桥接标头,说是):
mysectrust.h
\n\n#ifndef mysectrust_h\n#define mysectrust_h\n\n#include <Security/Security.h>\n\nSecTrustRef changeHostForTrust(SecTrustRef trust);\n\n#endif /* mysectrust_h */\nRun Code Online (Sandbox Code Playgroud)\n\nmysectrust.c
\n\n#include "mysectrust.h"\n\nSecTrustRef changeHostForTrust(SecTrustRef trust)\n{\n CFMutableArrayRef newTrustPolicies = CFArrayCreateMutable(\n kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);\n\n SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.example.com"));\n\n CFArrayAppendValue(newTrustPolicies, sslPolicy);\n\n#ifdef MAC_BACKWARDS_COMPATIBILITY\n /* This technique works in OS X (v10.5 and later) */\n\n SecTrustSetPolicies(trust, newTrustPolicies);\n CFRelease(oldTrustPolicies);\n\n return trust;\n#else\n /* This technique works in iOS 2 and later, or\n OS X v10.7 and later */\n\n CFMutableArrayRef certificates = CFArrayCreateMutable(\n kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);\n\n /* Copy the certificates from the original trust object */\n CFIndex count = SecTrustGetCertificateCount(trust);\n CFIndex i=0;\n for (i = 0; i < count; i++) {\n SecCertificateRef item = SecTrustGetCertificateAtIndex(trust, i);\n CFArrayAppendValue(certificates, item);\n }\n\n /* Create a new trust object */\n SecTrustRef newtrust = NULL;\n if (SecTrustCreateWithCertificates(certificates, newTrustPolicies, &newtrust) != errSecSuccess) {\n /* Probably a good spot to log something. */\n\n return NULL;\n }\n\n return newtrust;\n#endif\n}\nRun Code Online (Sandbox Code Playgroud)\n\n当然,将www.example.com上面的代码替换为您的主机名。
然后,在 Xcode 项目中找到桥接标头,projectname-Bridging-Header.h并附加以下行:
#import "mysectrust.h"\nRun Code Online (Sandbox Code Playgroud)\n\n现在你可以从 Swift 调用这个函数,例如:
\n\nfunc whatever(trust: SecTrustRef){\n\n let newTrust = changeHostForTrust(trust) // call to C function\n ...\n} \nRun Code Online (Sandbox Code Playgroud)\n