首先是服务器端:有一个内部可达的apache服务器,有几个虚拟主机。对于http(sans的'!)请求,我使用IP作为URL并在Host-Headerfield中添加主机名。
这非常有效。
但是当我建立SSL连接时,我遇到的问题似乎与SNI有关。
我找到了这个Overriding TLS Chain Validation Correctly并在我的代码中实现了它。
所以我更新了信任
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
但我仍然从服务器获得400。
更新:URLSession
确实支持SNI但我的问题是我需要添加额外的或更改hostname
中的SSLHandshake
。
首先是服务器的简短描述:服务器是一个Apache服务器,只能通过IP访问,但它有多个vhost,可以通过主机名在本地使用,但是当我从像iPhone这样的外部设备连接它们时,我必须在Host-Headerfield
中添加vhost的主机名。
所以我做的是:我用一个基于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请求是有效的,但是一旦使用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直接获得路由。
首先我们如何解决它:服务器工作者最终完成了他们的工作,并没有搞乱botchy设置。
我还在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方面,但我/强烈/建议不要这样,因为它是一项大量的工作。
分享和享受 - 奎因“爱斯基摩人!” Apple Developer Relations,开发人员技术支持,核心操作系统/硬件