【问题标题】:Alamofire with a self-signed certificate / ServerTrustPolicy带有自签名证书的 Alamofire / ServerTrustPolicy
【发布时间】:2015-12-09 18:46:59
【问题描述】:

我想使用 Alamofire 通过带有自签名证书的 https 连接与我的服务器通信。我的环境在本地主机上运行。我尝试连接,但响应一直是这样的:

Success: false
Response String: nil

我已经用下面的代码完成了:

import Foundation
import UIKit
import Alamofire

class MessageView: UITableViewController {

    let defaultManager: Alamofire.Manager = {
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "localhost": .DisableEvaluation
        ]

        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders

        return Alamofire.Manager(
            configuration: configuration,
            serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
        )
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        defaultManager
            .request(.GET, "https://localhost:3443/message")
            .responseJSON { _, _, result in
                print("Success: \(result.isSuccess)")
                print("Response String: \(result.value)")
            }
    }

}

我已经用这行 bash 创建了服务器端证书:

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

我不知道我做错了什么。帮助会很棒。

### 更新###

这是 cURL 请求。在我看来,没有问题,还是我错了?

curl -X GET https://localhost:3443/message -k -v

*   Trying ::1...
* Connected to localhost (::1) port 3443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
* Server certificate: teawithfruit
> GET /message HTTP/1.1
> Host: localhost:3443
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 1073
< Date: Tue, 15 Sep 2015 06:20:45 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact

[{"_id":"55f3ed2d81a334558241e2f4","email":"abc@def.com","password":"abc","name":"teawithfruit","language":"en","__v":0,"timestamp":1442049325159,"messages":[{"_id":"55f40553e568236589772c61","user":"55f3ed2d81a334558241e2f4","language":"en","message":"hello world","__v":0,"timestamp":1442055507301,"id":"55f40553e568236589772c61"},{"_id":"55f48b2b02e7b059b54e99f6","user":"55f3ed2d81a334558241e2f4","language":"en","message":"hello world","__v":0,"timestamp":1442089771312,"id":"55f48b2b02e7b059b54e99f6"}],"id":"55f3ed2d81a334558241e2f4"}]

### 更新 2 ###

抱歉回复晚了。 这是两个调试打印:

请求调试打印:

$ curl -i \
  -H "Accept-Language: en-US;q=1.0" \
  -H "Accept-Encoding: gzip;q=1.0,compress;q=0.5" \
  -H "User-Agent: Message/com.teawithfruit.Message (1; OS Version 9.0 (Build 13A340))" \
  "https://localhost:3443/message"

结果调试打印:

FAILURE: Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://localhost:3443/message, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://localhost:3443/message}

### 更新 3 ###

这是可能存在 ATS 问题的完整错误?

nil
$ curl -i \
  -H "Accept-Language: en-US;q=1.0" \
  -H "Accept-Encoding: gzip;q=1.0,compress;q=0.5" \
  -H "User-Agent: Message/com.teawithfruit.Message (1; OS Version 9.0 (Build 13A340))" \
  "https://localhost:3443/message"
2015-10-17 15:10:48.346 Message[25531:1001269] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
FAILURE: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7fdc3044b740>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=<CFArray 0x7fdc2a7ca300 [0x10f7037b0]>{type = immutable, count = 1, values = (
  0 : <cert(0x7fdc31d31670) s: teawithfruit i: teawithfruit>
)}, NSUnderlyingError=0x7fdc30064bd0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7fdc3044b740>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7fdc2a7ca300 [0x10f7037b0]>{type = immutable, count = 1, values = (
  0 : <cert(0x7fdc31d31670) s: teawithfruit i: teawithfruit>
)}}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://localhost:3443/message, NSErrorFailingURLStringKey=https://localhost:3443/message, NSErrorClientCertificateStateKey=0} 
Success: false
Response String: nil

【问题讨论】:

  • 你能用cURL成功发出请求吗?如果是,您能否在result 上添加cURL 示例和输出以及debugPrint
  • 我已经更新了帖子。我看不出有什么问题。你呢?
  • requestlet request = defaultManager.request(...) 时,您能否发布debugPrint(request) 的输出。您能否也发布debugPrint(result) 的输出?没有这些,就很难提供帮助。
  • 抱歉迟到了。我已经添加了它们。谢谢你的帮助。 :)
  • 嘿,你修好了吗??

标签: ios swift https alamofire


【解决方案1】:

您需要在创建ServerTrustPolicy 字典时添加port 域。

let defaultManager: Alamofire.Manager = {
    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "localhost:3443": .DisableEvaluation
    ]

    let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
    configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders

    return Alamofire.Manager(
        configuration: configuration,
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )
}()

【讨论】:

  • 感谢您的回答。你说得对。我忘了添加端口。但是如果我添加端口,我会收到以下错误:Message[4401:95209] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
  • 你有什么别的想法吗?
  • 现在您似乎遇到了 ATS。更多信息here。您能否在问题的更新中发布新错误的完整详细信息?
  • 嘿,我已经更新了问题。它看起来像一个 SSL 错误。也许你知道更多?感谢您的帮助。
  • 如果我在 AppDelegate 使用这个解决方案,我的所有代码都可以使用变量 defaultManager 吗?是否可以配置默认 SessionManager 并继续使用 Alamofire.request 而不是 defaultManager.request?
【解决方案2】:

对于 Swift 4:

private static var Manager : Alamofire.SessionManager = {
    // Create the server trust policies
    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "your domain goes here": .disableEvaluation
    ]
    // Create custom manager
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
    let man = Alamofire.SessionManager(
        configuration: URLSessionConfiguration.default,
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )
    return man
}()

那你这样称呼它:

Manager.upload(body.data(using: .utf8)!, to: url, method: .post, headers: headers)

Credits to Cnoon

【讨论】:

    【解决方案3】:

    我的自签名 https 方法。 ServerTrustPolicyManager 是一个open 类,它的serverTrustPolicy 函数也是open。所以它可以被覆盖。

    在我的情况下,服务器列表将来会增长。如果我对 https 列表进行硬编码,我将需要在添加新的 https 服务器时维护该列表。因此,我决定重写 ServerTrustPolicyManager 类以满足我的需求。

    // For Swift 3 and Alamofire 4.0
    open class MyServerTrustPolicyManager: ServerTrustPolicyManager {
    
        // Override this function in order to trust any self-signed https
        open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
            return ServerTrustPolicy.disableEvaluation
        }
    }
    

    那么,

        let trustPolicies = MyServerTrustPolicyManager(policies: [:])
        let manager = Alamofire.SessionManager(configuration: sessionConfig, delegate: SessionDelegate(), serverTrustPolicyManager: trustPolicies)
    

    【讨论】:

      【解决方案4】:

      所以我知道已经过去了一段时间,但我遇到了完全相同的问题。我找到了具有上述答案的解决方案。我必须在 trustPolicies 中添加两件事:

      let defaultManager: Alamofire.Manager = {
          let serverTrustPolicies: [String: ServerTrustPolicy] = [
               // Here host with port (trustPolicy is my var where I pin my certificates)
              "localhost:3443": trustPolicy
               //Here without port
               "localhost": .disableEvaluation
          ]
      
          let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
          configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
      
          return Alamofire.Manager(
              configuration: configuration,
              serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
          )
      }()
      

      还要在 Info.plist 中添加:

      <key>AppTransportSecurity</key>
      <dict>
        <key>AllowsArbitraryLoads</key>
            <true/>
      </dict>
      

      【讨论】:

        猜你喜欢
        • 2017-11-01
        • 1970-01-01
        • 2014-05-05
        • 2015-06-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多