【问题标题】:How to get custom NSURLProtocol working with SNI如何让自定义 NSURLProtocol 与 SNI 一起使用
【发布时间】:2017-07-03 11:10:25
【问题描述】:

首先是服务器端: 有一个内部可访问的 apache 服务器,其中包含多个虚拟主机。 对于 http (sans 's'!) 请求,我使用 IP 作为 URL 并在 Host-Header 字段中添加主机名。

效果很好。

但是当我建立 SSL 连接时,我遇到了似乎与 SNI 相关的问题。

我找到了这个Overriding TLS Chain Validation Correctly 并在我的代码中实现了它。

所以我更新了对

的信任
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

但我仍然从服务器获得 400。

更新: URLSession 确实支持 SNI,但我的问题是我需要添加额外的或更改 SSLHandshake 中的 hostname

所以首先对服务器做一个简短的描述: 服务器是一个 Apache 服务器,只能通过 IP 访问,但它有多个虚拟主机,可通过主机名在本地使用,但是当我从 iPhone 等外部设备连接到它们时,我必须在 @ 添加虚拟主机的主机名987654326@.

所以我要做的是:我使用基于 IP 的 URL 创建一个 URLRequest,然后添加带有主机名的 HOST Headerfield

if let url = URL("https://192.168.178.54:8890") {
    var request = URLRequest(url: url)
    request.addValue("foobar:8890", forHTTPHeaderField: "Host")
    …
}

这适用于非安全的 http-Requests,但一旦使用 https,服务器就会返回“400 Bad request”并且 http-ssl-error.log 包含以下错误:

[Tue Jul 11 09:35:51 2017] [error] Hostname 192.168.178.54 provided via SNI and hostname foobar provided via HTTP are different

这是因为默认情况下 SSLHandshake 使用 URL 中提供的值,在我的例子中是 IP。

我现在想弄清楚的是如何在 SSLHandshake 中提供不同的主机名,或者提供类似自己的 DNS 解析器的东西,我仍然可以使用基于主机名的 URL,但 iOS 可以直接进行路由。

【问题讨论】:

  • SNI 由 NSURLSession 原生支持。您无需对代码进行任何修改即可使其正常工作。 openssl s_client -connect hostname.com:443 对您的服务器有何评价?
  • 感谢您的评论。我的服务员的回答有点误导。是的,URLSession 支持 SNI,它在正常情况下工作,但我必须更改 SSLHandshake 中的主机名……而这对于 URLSession 是不可能的。我将更新我的 OP 以使其更清晰
  • 发布一些关于如何更新挑战的代码。
  • 这个问题与func urlSession(_ session:didReceivechallenge:completionHandler:) 无关,它与在 URLSession 启动之前发生的 SSL 握手有关。我打开了一个 TSI 并从 Apple 获得了听起来不太好的信息: API 级别的问题在于,URL 是“主机”由两个不同的系统组件(TLS 引擎和 HTTP 协议实现)检索,但您实际上只能控制其中一个(HTTP 实现)通过 URLProtocol)
  • 你有没有机会解决这个问题并记得是怎么做到的?

标签: ios swift nsurlsession sni nsurlprotocol


【解决方案1】:

首先我们是如何解决它的:服务员们终于做好了他们的工作,没有乱搞乱七八糟的设置。

回到我还在Apple Dev Forums@ 中发布了我的问题

我还从我的 TSI 收到了这个:

将您的事件转告给我,因为我通常在这两个方面都处于领先地位 DTS 中的 NSURLSession 和 TLS 问题(我当时不在办公室 你的事件最初是进来的)。

回到您的技术问题,我似乎回复了您 通过您为此创建的 DevForums 线程。

https://forums.developer.apple.com/thread/82179

这个回答相当简短,但确实涵盖了要点:

  • 无法在 NSURLSession 级别配置 SNI 名称

  • 我推荐的替代方法是使用.local DNS 名称

如上所述,我的 DevForums 回复相当简短,所以如果您有 关于后者的任何后续问题,我很乐意回答 在这里。

您/可以/覆盖网络中较低级别的 SNI 名称 堆栈,即 CFSocketStream(通过 NSSStream 和 CFStream API)和安全传输。理论上你可以实现 您自己的 NSURLProtocol 子类中的 HTTP 协议层,使用 这些 API 用于 TLS-over-TCP 方面,但我 /strongly/ 建议不要这样做,因为它的工作量很大。

分享和享受 ——奎因“爱斯基摩人!” Apple 开发者关系、开发者技术支持、核心操作系统/硬件

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2016-01-13
    • 1970-01-01
    • 2017-07-27
    • 2019-08-14
    相关资源
    最近更新 更多