閱讀735 返回首頁    go 技術社區[雲棲]


iOS 防 DNS 汙染方案調研 --- WebView 業務場景

概述

本文主要介紹,防 DNS 汙染方案在 WebView 場景下所遇到的一些問題,及解決方案,也會涉及比如:“HTTPS+SNI” 等場景。

麵臨的問題

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 相關的問題,可以參照裏麵的方法解決。

使用 NSURLProtocol 攔截 NSURLSession 請求丟失 body

方案如下:

  1. 換用 NSURLConnection
  2. 將 body 放進 Header 中
  3. 使用 HTTPBodyStream 獲取 body,並賦值到 body 中

    //處理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];
        }
    }
    }
    
    

使用 -[WKWebView loadRequest] 同樣會遇到該問題,按照同樣的方法修改。

302重定向問題

上麵提到的 Cookie 方案無法解決302請求的 Cookie 問題,比如,第一個請求是 https://www.a.com ,我們通過在 request header 裏帶上 Cookie 解決該請求的 Cookie 問題,接著頁麵302跳轉到 https://www.b.com ,這個時候 https://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 請求。

Cookie相關問題

單獨成篇: 《防 DNS 汙染方案調研---iOS HTTPS(含SNI) 業務場景(四)-- Cookie 場景》

參考鏈接

相關的庫:

相關的文章:

可以參考的Demo:

走過的彎路

誤以為 iOS11 新 API 可以原生攔截 WKWebView 的 HTTP/HTTPS 網絡請求

參考:Deal With WKWebView DNS pollution problem in iOS11

最後更新:2017-09-13 14:33:01

  上一篇:go  Android Webview場景下防止dns劫持的探索
  下一篇:go  iOS 防 DNS 汙染方案調研 --- Cookie 業務場景