iOS HTTPDNS集成,结合AFNetwork进行“ip直连”
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS HTTPDNS集成,结合AFNetwork进行“ip直连”相关的知识,希望对你有一定的参考价值。
参考技术A 本期是通过NSURLProtocol拦截的方式替换ip,包括SNI的处理。后期有时间会有一章通过hook网络框架AFN的方式,这种方式也无需改变AFN源码,包括在HTTPS证书校验的过程。而本文主要针对HTTPS协议进行说明,HTTP协议没有SSL/TLS的证书验证的过程,处理起来比较简单,也无需用到CFNetwork,所以暂时不做讲解。还有一篇 结合SDWebImage对HTTP协议进行"ip直连" 的文章。无论是HTTP还是HTTPS都可结合AFNetwork和SDWebImage进行"ip直连",其中原理都是相通的。若有不足或误区,盼请指正。大概说一下本章内容:本文对HTTPDNS做一个较为详细的讲解,在看本文之前,您需要对系统偏底层的CFNetwork网络框架有一个比较基础的认知。整体总结为以下几点。
首先,DNS解析的目的就是通过某个域名:host(www.xxx.com)找到ip地址(111.111.1.1)。对于HTTPDNS的含义,用通俗简单一点语言解释。就是跳过运营商的DNS解析,通过ip地址直接精准对目标服务器进行连接。可避免被劫持,并大大缩短DNS解析时间,这也是对网络请求的一个重要优化环节(DNS优化)。
我们都知道一般的request发出去之后的第一步就是对请求域名进行解析,而一般情况下我们的解析都是走运营商的LocalDNS,首先LocalDNS会对请求过的数据做缓存,因为缓存的时效性,我们想拿到最新最准确的数据时就会受限。其次,在这个DNS解析的过程中容易被外界劫持,注入一些未知的内容(像广告一类)后返回,甚至返回一个全新的ip给用户,可能危及到用户的个人隐私。而HTTPDNS是让用户绕过LocalDNS,在发送请求之前在本地就把host换成ip,直接对准目标服务器,这样就无需去问运营商服务器索要ip了,本来耗时不短的DNS的解析过程耗已在本地客户端完成了,所以DNS解析的时间就大大缩短了。
至于怎么拿到host对应的ip呢,因为客户端没法拿到当前host对应的最优ip(比如根据发送请求的地域不同等原因,对应的最优ip也可能不同),所以最好不要写死在客户端,而是通过外界拿到。两种方案:1、服务器直接下发,此种情况也是比较复杂,因为涉及的很多容灾的处理,比如在ip链接失败的时候,需要用LocalDNS做兜底,并向服务器上传错误日志,询问是否需要更新本地ip集合等等一系列复杂的操作。2、通过三方拿到,比如DNSPOD,阿里等。个人建议选择支持预处理的三方,在启动app的时候,预先拿到需要的ip集合,比如阿里。
此文主要通过NSURLProtocol拦截请求的方式进行“ip直连”,以及post请求时,body“丢失”问题处理,SNI场景处理,利用CFNetwork对SNI的处理。先简单介绍一下NSURLProtocol,NSURLProtocol是苹果提供给开发者们专门用来劫持网络请求的一个抽象类,所以一般用到的时候选择用继承NSURLProtocol的方式,本文中的WYCustomURLProtocol就只这样一个子类。先了解几个重要的api:
1、+ (BOOL)canInitWithRequest:(NSURLRequest *)request;// 通过协议或是域名判断哪些域名的请求需要拦截的就返YES,反之返NO。
2、+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request; // 上面方法的返YES时,会走到这个方法,你可以直接返回request,也可以重定向一个request返回。
3、- (void)startLoading;// 重定向的request就是从此发出去的
4、- (void)stopLoading; // 当cancel请求的时候,会调用此方法。
接下来就开始附上code了,要用UrlProtocol之前需要对之进行注册。
第1步、在初始化AFHTTPSessionManager的时候,对其进行注册:如图 1
第2步、若你使用到了YTK框架,那么可以这样初始化,此处为了便于理解所以引用了YTK,实际操作的时候,建议对外提供一个注册接口,不要直接用此种直接依赖TYK的方式,以免污染HTTPDNS部分。 图 2
第3步、对于要过滤拦截的域名需在此方法判断 图 3
第4步、请求ip替换host的过程,并给header添加host, 如图 4。此处只要能正确替换,大家可以各显神通。
其中的wy_bodyForPost目的是为了取回body,方法体如图 5
此处需要说明一下,通过NSURLProtocol拦截的post请求的body并非真的丢失了,只是body数据在URL loading system中到达这里之前就已被转成stream了。可以在request.HTTPBodyStream中解析它。
第5步、利用CFNetwork重新构建C语言的request,并发送。如图 6和 图7
什么是SNI场景呢,SNI全称 Server Name Indication,是TLS的扩展。我们知道一个服务器可能对应了多个域名的情况,客户端与服务端在建立HTTPS连接的过程中要进行SSL/TLS握手。整个握手过程步骤分5步:
1、客户端发起握手请求,携带随机数、支持算法列表等参数。
2、服务端收到请求,选择合适的算法,下发公钥证书和随机数。
3、客户端对服务端证书进行校验,并发送随机数信息,该信息使用公钥加密。
4、服务端通过私钥获取随机数信息。
5、双方根据以上交互的信息生成session ticket,用作该连接后续数据传输的加密密钥。
而握手失败就发生在第3步,客户端验证后端给的证书过程如下:
1、客户端用本地的根证书解开证书链,确认服务端下发的证书是由可信任机构颁发。
2、客户端检查证书的domain域和扩展域,验证是否包含本次请求的host。
若是在握手过程中客户端要是没有指定需要访问的目标域名,这就会导致一个问题:如果一台服务机对应了多个域名,每个域名对应的证书也不一样,那服务端也不知道该返回给客户端哪一套证书进行校验,导致第3步的校验失败,以至握手失败。但若是我们指定该SSL/TLS的目标域名,那服务端就知道该返回那一套证书了,即可通过证书验证,握手成功。
那么如何指定目标域名呢?我们可以为SNI扩展字段添加一个host。而ios的上层网络库NSURLConnection/NSURLSession没有提供对SNI字段进行配置的接口,所以要用到Socket层级的底层网络库CFNetwork,对SNI字段进行配置。如图 8
补充:1、为什么要在SNI的扩展里面添加传host,我不是在header传了host了吗?此处做一个简要说明:由于HTTP的host字段在header中。而SSL/TLS的握手以及证书验证都是在HTTP开始之前,所以header里面的host对于如何判断选取证书是没有关系的。这个时候,SSL/TLS协议的HELLO中增加了一个server name字段(SNI扩展字段),让HTTP的客户端可以提前设置host,从而使服务端在SSL/TLS的握手阶段可以选择正确的证书。在SSL/TLS握手过程中,若不是SNI的情况,意味着服务器只对应了一个域名,一套证书,所以可以直接返回即为正确的证书,这也是为什么不是SNI的情况下无需配置SNI的原因。前面我们说了SNI呢是一对多的情况,在拿不到host的时候不知道返回哪一套证书,就会返回默认的一套或不返回,这个时候我们就需要在配置SNI了,添加server name字段,对应的value即为host值。(比如:若是你需要通过HTTPS访问CDN节点资源,而CDN的节点往往服务了多个域名,所以需要通过SNI指定具体的域名证书进行通信。)
在证书校验的过程中解决了SNI的问题之后呢,服务端会返回给客户端一个与请求域名相匹配的证书,在客户端验证的时候若是默认取的请求地址中的host,而此时默认host早被我们换成了ip地址了,与证书是不匹配的,所以我们需要将header中的host取出进行证书验证。数据处理过程如图9 ;证书验证过程如图 10,一般SecTrustResultType的值为kSecTrustResultProceed或kSecTrustResultUnspecified表明验证通过。
下面主要是一些读取数据过程中对数据的处理,细节就不多说了,基本都是更CFNetwork相关部分。 如图 11
关于HTTPDNS,你知道多少?
什么是HTTPDNS?
HTTPDNS是面向多端应用(移动端APP,PC客户端应用)的域名解析服务,具有域名防劫持、精准调度、实时解析生效的特性。
HTTPDNS工作流程
客户端直接访问HTTPDNS接口,获取业务在域名配置管理系统上配置的访问延迟最优的IP。获取到IP后就直接往此IP发送业务协议请求。以HTTP请求 为例,通过在header中指定host字段,向HTTPDNS返回的IP发送标准的HTTP请求即可。
HTTPDNS特性优势
1、域名防劫持
-
- 绕过运营商的Local DNS,避免域名劫持。
- 基于HTTP协议的设计适用于几乎所有的网络环境,同时保留了鉴权、HTTPS等更高安全性的扩展能力,避免恶意攻击劫持行为。
- 商业化的HTTPDNS服务缓存管理有严格的SLA保障,避免了Local DNS的缓存污染问题。
2、精准调度
-
- 部分Local DNS供应商为了降低运营成本,会将解析请求转发给其他供应商的Local DNS节点会严重影响域名解析的精准性。
- HTTPDNS将终端用户的IP信息直接交付给权威DNS, 从而忽略Local DNS IP信息,根据终端用户的IP信息进行精准调度,避免Local DNS的坐标干扰。
3、实时生效
-
- Local DNS首次查询或超过缓存时间的查询,需要递归遍历多个DNS服务器以获取最终的解析结果, 增加了网络请求的延时时间。
- HTTPDNS严格遵循DNS TTL限制进行缓存更新, 用户在权威DNS变更的解析结果将快速同步。
应用场景
场景一:移动应用域名防劫持
【场景描述】
域名劫持一直是困扰许多开发者,其表现即域名A应该返回的DNS解析结果IP1被恶意替换为了IP2,导致A的访问失败或访问了一个不安全的站点。
【解决方案】
域名防劫持:使用HTTP(HTTPS)协议进行域名解析,域名解析请求直接发送至HTTPDNS服务器,绕过运营商Local DNS,避免域名劫持问题;
调度精准:由于运营商策略的多样性,其 Local DNS 的解析结果可能不是最近、最优的节点,HTTPDNS能直接获取客户端 IP,基于客户端 IP 获得最精准的解析结果,让客户端就近接入业务节点。
场景二:解决视频推拉流卡顿
【场景描述】
视频直播类App当前已经普遍采用CDN来实现访问加速,但还是经常遇到推拉流慢、卡顿的问题。这类问题一般是由于调度不精准、域名劫持、终端手机接入网络动态切换等因素导致,结合使用CDN和HTTPDNS可以比较完美解决此类问题。
【问题解决】
轻服务端解决方案:当推流或者拉流出现服务质量问题(如慢、卡顿)时,使用HTTPDNS获取最新的最佳服务质量节点,并利用最新的节点进行推拉流。
DEMO体验
体验入口:https://www.aliyun.com/product/httpdns
如果您是首次开通,会有150万次免费解析额度,可进行免费体验!如果您是老用户,现在还有阿里云官网的大额折扣优惠,可进行超低价体验!
本文为阿里云原创内容,未经允许不得转载。
以上是关于iOS HTTPDNS集成,结合AFNetwork进行“ip直连”的主要内容,如果未能解决你的问题,请参考以下文章