Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS 防 DNS 污染方案调研(三)--- WebView 业务场景 #11

Open
ChenYilong opened this issue Jul 20, 2017 · 10 comments
Open

iOS 防 DNS 污染方案调研(三)--- WebView 业务场景 #11

ChenYilong opened this issue Jul 20, 2017 · 10 comments
Labels

Comments

@ChenYilong
Copy link
Owner

ChenYilong commented Jul 20, 2017

iOS防DNS污染方案调研---WebView业务场景

对应的GitHub仓库镜像地址在这里 ,欢迎提PR进行修改。

概述

本文主要介绍,防 DNS 污染方案在 WebView 场景下所遇到的一些问题,及解决方案,也会涉及比如:“HTTPS+SNI” 等场景。

面临的问题

/one more thing/

WKWebView 无法使用 NSURLProtocol 拦截请求

方案如下:

  1. 换用 UIWebView
  2. 使用私有API进行注册拦截

换用 UIWebView 方案不做赘述,说明下使用私有API进行注册拦截的方法:

//注册自己的protocol
   [NSURLProtocol registerClass:[CustomProtocol class]];

   //创建WKWebview
   WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc] init];
   WKWebView * wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) configuration:config];
   [wkWebView loadRequest:webViewReq];
   [self.view addSubview:wkWebView];

   //注册scheme
   Class cls = NSClassFromString(@"WKBrowsingContextController");
   SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
   if ([cls respondsToSelector:sel]) {
       // 通过http和https的请求,同理可通过其他的Scheme 但是要满足ULR Loading System
       [cls performSelector:sel withObject:@"http"];
       [cls performSelector:sel withObject:@"https"];
   }

使用私有 API 的另一风险是兼容性问题,比如上面的 browsingContextController 就只能在 iOS 8.4 以后才能用,反注册 scheme 的方法 unregisterSchemeForCustomProtocol: 也是在 iOS 8.4 以后才被添加进来的,要支持 iOS 8.0 ~ 8.3 机型的话,只能通过动态生成字符串的方式拿到 WKBrowsingContextController,而且还不能反注册,不过这些问题都不大。至于向后兼容,这个也不用太担心,因为 iOS 发布新版本之前都会有开发者预览版的,那个时候再测一下也不迟。对于本文的例子来说,如果将来哪个 iOS 版本移除了这个 API,那很可能是因为官方提供了完整的解决方案,到那时候自然也不需要本文介绍的方法了。

注意避免执行太晚,如果在 - (void)viewDidLoad 中注册,可能会因为注册太晚,引发问题。建议在 +load 方法中执行。

然后同样会遇到 《iOS SNI 场景下的防 DNS 污染方案调研》 里提到的各种 NSURLProtocol 相关的问题,可以参照里面的方法解决。

Cookie相关问题

单独成篇: 《防 DNS 污染方案调研---iOS HTTPS(含SNI) 业务场景(四)-- Cookie 场景》

302重定向问题

上面提到的 Cookie 方案无法解决302请求的 Cookie 问题,比如,第一个请求是 http://www.a.com ,我们通过在 request header 里带上 Cookie 解决该请求的 Cookie 问题,接着页面302跳转到 http://www.b.com ,这个时候 http://www.b.com 这个请求就可能因为没有携带 cookie 而无法访问。当然,由于每一次页面跳转前都会调用回调函数:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

可以在该回调函数里拦截302请求,copy request,在 request header 中带上 cookie 并重新 loadRequest。不过这种方法依然解决不了页面 iframe 跨域请求的 Cookie 问题,毕竟-[WKWebView loadRequest:]只适合加载 mainFrame 请求。

参考链接

相关的库:

相关的文章:

可以参考的Demo:

走过的弯路

误以为 iOS11 新 API 可以原生拦截 WKWebView 的 HTTP/HTTPS 网络请求

参考:Deal With WKWebView DNS pollution problem in iOS11

@ChenYilong ChenYilong changed the title iOS WebView 场景下的防 DNS 污染方案调研 防 DNS 污染方案调研---iOS HTTPS(含SNI) 业务场景(二)-- WebView 场景 Aug 8, 2017
@ChenYilong ChenYilong changed the title 防 DNS 污染方案调研---iOS HTTPS(含SNI) 业务场景(二)-- WebView 场景 防 DNS 污染方案调研---iOS HTTPS(含SNI) 业务场景(三)-- WebView 场景 Aug 8, 2017
@ChenYilong ChenYilong changed the title 防 DNS 污染方案调研---iOS HTTPS(含SNI) 业务场景(三)-- WebView 场景 iOS 防 DNS 污染方案调研(三)--- WebView 业务场景 Aug 8, 2017
@ChenYilong
Copy link
Owner Author

ChenYilong commented Aug 9, 2017

//TODO: 下一步需要测试下,拦截所有网络请求这个方案与原生方式的性能对比,对比方式见SNI篇。

测试时需要加载非常复杂的页面,比如一个页面上百次的网络请求,比如:测试1测试2
等。

测试系统:iOS 8 - iOS 11,对比Safari、系统WebView原生加载、拦截所有网络请求这个方案。

@JeroldLiu777
Copy link

你好,可以请教个问题吗?WKWebView在NSURLProtocol里面有post请求body丢失的问题,有解决方案吗?

@ChenYilong
Copy link
Owner Author

@lucifer717 上面提到了一种方法,在 #12 这里也进行了说明,你看下能否解决你的问题。

@karosLi
Copy link

karosLi commented Aug 28, 2017

/**使用 NSURLProtocol 拦截 NSURLSession 请求丢失 body

方案如下:

换用 NSURLConnection
将 body 放进 Header 中
使用 HTTPBodyStream 获取 body,并赋值到 body 中
**/

请问这里的把 body 放进 header 里能说的更清楚吗?在哪里放,h5放还是还是native放,如果native放,怎么保证后续的请求都能放,如果放在h5,怎么保证第三方加入这个header,这也是问题。

所以请问楼主有在实践中使用过你的方案吗?

@ChenYilong
Copy link
Owner Author

ChenYilong commented Aug 28, 2017

使用测试链接进行测试,一个页面有80余个网络请求,测试对比:

其中的网络请求:多数为 HTTPS 的图片、JS、CSS资源文件。

加载完成上面的测试链接,平均耗时:

防DNS污染方案 原生方案
16+1.9+1.6+2.4+2.7+1.5+3.9+2.2+1.2+.3=33.7/10=3.37 7+1.4+4.0+2.3+1.3+1.8+1.3+1.9+1.9+2=24.9/10=2.49

均采用步骤:

第一次安装app,第一次打开页面的方式,之后的测试是采用密集点击进页面加载网页。

可以看到第一次网络请求差距较大,之后的网络请求延迟与原生请求接近。

性能消耗集中在证书验证部分。

@ChenYilong
Copy link
Owner Author

ChenYilong commented Sep 26, 2017

上文有误:

WKWebView不能使用下面的方法来恢复body内容:

下面这个方法仅仅适用于HTTPBodyStream有内容的场景,一般的UIWebView与NSURLSession请求都可以,但是参考:

由于 WKWebView 在独立进程里执行网络请求。一旦注册 http(s) scheme 后,网络请求将从 Network Process 发送到 App Process,这样 NSURLProtocol 才能拦截网络请求。在 webkit2 的设计里使用 MessageQueue 进行进程之间的通信,Network Process 会将请求 encode 成一个 Message,然后通过 IPC 发送给 App Process。出于性能的原因,encode 的时候 HTTPBody 和 HTTPBodyStream 这两个字段被丢弃掉了(参考苹果源码:
https://github.com/WebKit/webkit/blob/fe39539b83d28751e86077b173abd5b7872ce3f9/Source/WebKit2/Shared/mac/WebCoreArgumentCodersMac.mm#L61-L88bug report: )。

//处理POST请求相关POST  用HTTPBodyStream来处理BODY体
- (void)handlePostRequestBody {
  if ([self.HTTPMethod isEqualToString:@"POST"]) {
      if (!self.HTTPBody) {
          uint8_t d[1024] = {0};
          NSInputStream *stream = self.HTTPBodyStream;
          NSMutableData *data = [[NSMutableData alloc] init];
          [stream open];
          while ([stream hasBytesAvailable]) {
              NSInteger len = [stream read:d maxLength:1024];
              if (len > 0 && stream.streamError == nil) {
                  [data appendBytes:(void *)d length:len];
              }
          }
          self.HTTPBody = [data copy];
          [stream close];
      }
  }
}

@jiehu5114
Copy link

wkwebview http请求拦截是无解的了

@kilolumen
Copy link

@ChenYilong WKWebView 支持302 跨域吗,或者说怎么设置

@ChenYilong

This comment has been minimized.

@ChenYilong
Copy link
Owner Author

ChenYilong commented Nov 26, 2020

我把 相关的方案汇总了下, 做了个视频, 有兴趣的可以看看 《WKWebView所有适配方案横向测评》 https://youtu.be/9egNGGGKET8 via 放在YouTube
其中ajax hook 部分, 可以解决DNS WebView场景这个问题;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants