iOS 9.3:发生 SSL 错误,无法与服务器建立安全连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36331623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:48:55  来源:igfitidea点击:

iOS 9.3 : An SSL error has occurred and a secure connection to the server cannot be made

iosswiftssl-certificatealamofirensurlsession

提问by swiftBoy

I am getting following error with self signed certificate

我在使用自签名证书时遇到以下错误

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made.

错误域=NSURLErrorDomain 代码=-1200 “发生 SSL 错误,无法与服务器建立安全连接。

while testing web-services for one of my demo app with

在为我的演示应用程序之一测试 Web 服务时

Note:before assuming its Duplicate, I would request please read it all the way,even same i have reported to apple dev forums

注意:在假设它是重复的之前,我会要求请一直阅读它,即使我已经向苹果开发论坛报告过

Using Alamofire Library

使用Alamofire 库



func testAlamofireGETRequest() -> Void
    {
        Alamofire.request(.GET, "https://filename.hostname.net/HelloWeb/service/greeting/john")
            .responseJSON
        { response in
            print("Response JSON: \(response.result.value)")
        }
}


Using NSURLSession

使用NSURLSession



func testNSURLSessionRequest() -> Void {

        let session = NSURLSession.sharedSession()
        let urlString = "https://filename.hostname.net/HelloWeb/service/greeting/john"
        let url = NSURL(string: urlString)
        let request = NSURLRequest(URL: url!)
        let dataTask = session.dataTaskWithRequest(request) { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
            print("done, error: \(error)")

            //Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made.
        }
        dataTask.resume()
    }


I spent 2 days with no luck :(

there are bunch of questions already posted but nothing worked for me

我花了两天没有运气:(

已经发布了一堆问题,但对我没有任何帮助

posted Alamofire git issue

发布了 Alamofire git 问题



My Info.pistfile is updated for ATS settings this way

我的Info.pist文件以这种方式针对 ATS 设置进行了更新

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>filename.hostname.net</key>
            <dict>
                <key>NSExceptionRequiresForwardSecrecy</key>
                <false/>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>


Meanwhile I am able to get response for

同时我能够得到回应

http://filename.hostname.net

http://文件名.主机名.net

and https://google.com

HTTPS://google.com

butnot for https://filename.hostname.net

不是HTTPS://filename.hostname.net

Can anyone please suggest me why I am not able to get this working after huge efforts?

任何人都可以建议我为什么经过巨大努力后我无法完成这项工作吗?

回答by yaakov

At the command-line in OS X, run the following:

在 OS X 的命令行中,运行以下命令:

nscurl --ats-diagnostics https://filename.hostname.net --verbose

nscurl --ats-diagnostics https://filename.hostname.net --verbose

This will tell you what combinations of ATS settings will and will not permit iOS to access your site, and should point you towards what is wrong with your site.

这将告诉您哪些 ATS 设置组合将允许和不允许 iOS 访问您的站点,并应指出您的站点有什么问题。

It could be one or more of the following

它可能是以下一项或多项

  • Certificate hash algorithm (must be SHA-256 or above)
  • TLS version (must be 1.2)
  • TLS algorithms (must provide Perfect Forward Secrecy)
  • 证书哈希算法(必须是SHA-256或以上)
  • TLS 版本(必须是 1.2)
  • TLS 算法(必须提供完美的前向保密)

回答by TechnicalTophat

Apple has released the full requirements list for the App Transport Security.

Apple 已经发布了 App Transport Security 的完整要求列表。

Turned out that we were working with TLS v1.2 but were missing some of the other requirements.

原来我们正在使用 TLS v1.2,但缺少一些其他要求。

Here's the full check list:

这是完整的检查清单

  • TLS requires at least version 1.2.
  • Connection ciphers are limited to those that provide forward secrecy (see below for the list of ciphers.)
  • The service requires a certificate using at least a SHA256 fingerprint with either a 2048 bit or greater RSA key, or a 256bit or greater Elliptic-Curve (ECC) key.
  • Invalid certificates result in a hard failure and no connection.
  • The accepted ciphers are: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  • TLS 至少需要 1.2 版。
  • 连接密码仅限于提供前向保密的密码(请参阅下面的密码列表。)
  • 该服务需要至少使用 SHA256 指纹和 2048 位或更高的 RSA 密钥,或者 256 位或更高的椭圆曲线 (ECC) 密钥的证书。
  • 无效的证书会导致硬故障和无连接。
  • 接受的密码是: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

回答by Fennec

I presume the server you are trying to connect has invalid certificates or doesn't match up with the iOS 9 standards for ECC, Ciphers etc.

我认为您尝试连接的服务器的证书无效或与 ECC、密码等的 iOS 9 标准不匹配。

  • If you're using high-level networking APIs—NSURLSession, NSURLConnection, or anything layered on top of those—you don't have direct control over the cypher suites offered by the client. Those APIs choose a set of cypher suites using their own internal logic.

  • If you're using lower-level networking APIs—CFSocketStream, via its NSStream and CFStream APIs, and anything lower than that—you can explicitly choose the set of cypher suites you want to use. How you do this depends on the specific API.

  • 如果您使用的是高级网络 API——NSURLSession、NSURLConnection 或任何位于这些 API 之上的东西——您无法直接控制客户端提供的密码套件。这些 API 使用自己的内部逻辑选择一组密码套件。

  • 如果您使用的是较低级别的网络 API——CFSocketStream,通过其 NSStream 和 CFStream API,以及任何低于它的东西——您可以明确选择要使用的密码套件集。您如何执行此操作取决于特定的 API。

The standard practice is:

标准做法是:

  1. create the stream pair

  2. configure it for TLS

  3. get the Secure Transport context using the kCFStreamPropertySSLContext property

  4. configure specific properties in that context

  5. open the streams

  1. 创建流对

  2. 为 TLS 配置它

  3. 使用 kCFStreamPropertySSLContext 属性获取安全传输上下文

  4. 在该上下文中配置特定属性

  5. 打开溪流

You can see an example of this in the TLSTool sample code. Specifically, look at the TLSToolServerclass, where you can see exactly this sequence.

您可以在 TLSTool 示例代码中看到这样的示例。具体来说,查看TLSToolServer类,您可以在其中准确看到此序列。

In a very short context, you want to configure the stream in such a way that it bypasses the security, however, in the case of Alamofire you can do this directly by:

在一个非常简短的上下文中,您希望以绕过安全性的方式配置流,但是,在 Alamofire 的情况下,您可以通过以下方式直接执行此操作:

func bypassAuthentication() {
        let manager = Alamofire.Manager.sharedInstance
        manager.delegate.sessionDidReceiveChallenge = { session, challenge in
            var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
            var credential: NSURLCredential?
            if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
                disposition = NSURLSessionAuthChallengeDisposition.UseCredential
                credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
            } else {
                if challenge.previousFailureCount > 0 {
                    disposition = .CancelAuthenticationChallenge
                } else {
                    credential = manager.session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
                    if credential != nil {
                        disposition = .UseCredential
                    }
                }
            }
            return (disposition, credential)
        }
    }

let me know if that helps. Thank you!

如果这有帮助,请告诉我。谢谢!

回答by Hasya

I had same scenario and got stuck for a day. Try with your mobile data, if this works fine with your API, then problem with your network firewall. then enable SSL / TLS from firewall settings.

我有同样的场景并被卡住了一天。尝试使用您的移动数据,如果这适用于您的 API,则说明您的网络防火墙有问题。然后从防火墙设置启用 SSL / TLS。