Swift / XCode 7:NSURLSession / NSURLConnection HTTP加载失败(kCFStreamErrorDomainSSL,-9813)

时间:2015-09-22 12:22:58

标签: ssl ios9 xcode7 ampps tls1.2

我已经使用openssl和sha 256创建了一个自签名证书,如下所示:

openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -keyout server.key -out server.crt

我已经通过配置httpd-ssl.conf文件在我的AMPPS服务器中正确安装了它。如果我尝试在网络浏览器上执行:

https://localhost

我正确地看到该连接使用TLS 1.2。 当我在iOS 9模拟器下运行我的应用程序时,我猜错了(9813),因为我的证书是自签名的。 对于我的测试用户,有没有办法启用它? 我在这里读到我应该为AppDelegate.swift类添加一些功能,但似乎它没有用。

这是我收到的完整错误消息:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Optional(Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this  server is invalid. You might be connecting to a server that is pretending to be  “localhost” which could put your confidential information at risk." UserInfo= {NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7fc492d54cf0>,  NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?,  _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813,  NSErrorPeerCertificateChainKey=<CFArray 0x7fc492cc4bc0 [0x103cb67b0]>{type =  immutable, count = 1, values = (
0 : <cert(0x7fc492d520c0) s: Lorenzo Vinci i: Lorenzo Vinci>
)}, NSUnderlyingError=0x7fc492cc1370 {Error Domain=kCFErrorDomainCFNetwork   Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0,   kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fc492d54cf0>,  _kCFNetworkCFStreamSSLErrorOriginalValue=-9813, _kCFStreamErrorDomainKey=3,  _kCFStreamErrorCodeKey=-9813, kCFStreamPropertySSLPeerCertificates=<CFArray  0x7fc492cc4bc0 [0x103cb67b0]>{type = immutable, count = 1, values = (
0 : <cert(0x7fc492d520c0) s: Lorenzo Vinci i: Lorenzo Vinci>
)}}}, NSLocalizedDescription=The certificate for this server is invalid. You   might be connecting to a server that is pretending to be “localhost” which could    put your confidential information at risk.,    NSErrorFailingURLKey=https://localhost/protected/excogitoweb/mobile/loginM.php? username=lorenzo&password=lorenzo,  NSErrorFailingURLStringKey=https://localhost/protected/excogitoweb/mobile/loginM.p hp?username=lorenzo&password=lorenzo, NSErrorClientCertificateStateKey=0})

更新:适用于Mac OS X Yosemite
1)通过brew更新openssl到版本&gt; = 1.0.2d
2)TLS 1.2仅使用 apache 2.4工作实际上MAMP仍然使用apache 2.2。 解决方案:下载并安装最新版本的AMPPS,它运行的是apache 2.4.x版本 3)使用sha256(按照iOS 9的要求)使用

创建自签名证书
openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -keyout server.key -out server.crt

并将server.key和server.crt保存到/ Applications / AMPPS / apache / conf
中 4)确保在AMPPS的httpd.conf文件中加载了ssl模块 5)编辑文件/Applications/AMPPS/apache/conf/extra/httpd-ssl.conf添加:

<VirtualHost localhost:443>
   DocumentRoot "/Applications/AMPPS/www"
   ServerName localhost
   SSLEngine on
   SSLProtocol all -SSLv2 -SSLv3
   SSLHonorCipherOrder on
   SSLCertificateFile "/Applications/AMPPS/apache/conf/server.crt"
   SSLCertificateKeyFile "/Applications/AMPPS/apache/conf/server.key"
</VirtualHost>

里面

<IfModule ssl_module> ... </IfModule> 
6)每次使用NSURLSession引发错误9813时,iOS 9模拟器会惹恼你,证明证书无效(因为是自签名的)。因此,在您要使用NSURLSession的每个类中,例如,执行以下操作:

class LoginService: NSObject, NSURLSessionDelegate {

func URLSession(session: NSURLSession,
    task: NSURLSessionTask,
    didReceiveChallenge challenge: NSURLAuthenticationChallenge,
    completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?)
    -> Void) {

    completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}

...

func requestLoginWithURL (requestURL: NSURL, completionHandler: (success: Bool?) -> Void) {
    let configuration =
    NSURLSessionConfiguration.defaultSessionConfiguration()

    let urlRequest: NSURLRequest = NSURLRequest(URL: requestURL)

    let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())

    /*
    dataTaskWithRequest: creates an HTTP request for the specified URL request object, and calls a handler upon completion.
    */
    let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in

...
}

其中函数URLSession是一个委托,它将阻止应用程序因自签名证书而崩溃,并且无论如何它都会接受。

最后将此添加到您的info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <!--Include to allow subdomains-->
            <key>NSIncludesSubdomains</key>
            <true/>
            <!--Include to allow HTTP requests-->
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <!--
            <key>NSExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <false/> -->
        </dict>
    </dict>
</dict>

0 个答案:

没有答案