NSURLProtocol -- DNS劫持和Web資源本地化

什么是DNS劫持

DNS劫持就是通過(guò)劫持了DNS服務(wù)器,通過(guò)某些手段取得某域名的解析記錄控制權(quán)钞啸,進(jìn)而修改此域名的解析結(jié)果,導(dǎo)致對(duì)該域名的訪問(wèn)由原IP地址轉(zhuǎn)入到修改后的指定IP,其結(jié)果就是對(duì)特定的網(wǎng)址不能訪問(wèn)或訪問(wèn)的是假網(wǎng)址顿肺,從而實(shí)現(xiàn)竊取資料或者破壞原有正常服務(wù)的目的遮晚。
 常見(jiàn)的DNS劫持現(xiàn)象網(wǎng)絡(luò)運(yùn)營(yíng)商向網(wǎng)頁(yè)中注入了Javascript代碼性昭,甚至直接將我們的網(wǎng)頁(yè)請(qǐng)求轉(zhuǎn)發(fā)到他們自己的廣告頁(yè)面或者通過(guò)自己的DNS服務(wù)器將用戶請(qǐng)求的域名指向到非法地址

如何解決DNS被劫持

全站使用HTTPS協(xié)議,或者采用HttpDNS县遣,通過(guò)HTTP向自建的DNS服務(wù)器或者安全的DNS服務(wù)器發(fā)送域名解析請(qǐng)求糜颠,然后根據(jù)解析結(jié)果設(shè)置客戶端的Host指向,從而繞過(guò)網(wǎng)絡(luò)運(yùn)營(yíng)商的DNS解析服務(wù)萧求。

本文的解決方案

客戶端對(duì)WebView的html請(qǐng)求進(jìn)行DNS解析其兴。優(yōu)先使用阿里、騰訊夸政、114等公共安全的DNS服務(wù)器解析客戶端的所有指定域名的http請(qǐng)求元旬。相對(duì)來(lái)講我們自己的服務(wù)域名變化較少,對(duì)此我們做了一個(gè)白名單,把凡是訪問(wèn)包含我們公司域名的請(qǐng)求都必須通過(guò)白名單的解析和DNS驗(yàn)證匀归。從而杜絕被劫持的情況出現(xiàn)坑资,這時(shí)候NSURLProtocol就派上用場(chǎng)了。

NSURLProtocol

這是一個(gè)抽象類穆端,所以在oc中只能通過(guò)繼承來(lái)重寫父類的方法袱贮。

@interface XRKURLProtocol : NSURLProtocol
@end

然后在AppDelegate的 application:didFinishLaunchingWithOptions: 方法或者程序首次請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)之前去注冊(cè)這個(gè)NSURLProtocol的子類

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     [NSURLProtocol registerClass:[XRKURLProtocol class]];
}

注冊(cè)了自定義的urlProtocol子類后,之后每一個(gè)http請(qǐng)求都會(huì)先經(jīng)過(guò)該類過(guò)濾并且通過(guò)+canInitWithRequest:這個(gè)方法返回一個(gè)布爾值告訴系統(tǒng)該請(qǐng)求是否需要處理体啰,返回Yes才能進(jìn)行后續(xù)處理攒巍。

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
        return NO;
    }

    //http和https都會(huì)出現(xiàn)dns劫持情況,都需要處理
    NSString *scheme = [[request URL] scheme];
    if (([scheme caseInsensitiveCompare:@"http"] == NSOrderedSame)) {
        // 判斷請(qǐng)求是否為白名單
        NSArray *whiteLists = [XRKConfigManager sharedManager].whiteList;
        if (whiteLists && [whiteLists isKindOfClass:[NSArray class]]) {
            for (NSString *url in whiteLists) {
                if (request.URL.host && [request.URL.host hasSuffix:url]) {
                    return YES;
                }
            }
        }
    }

    return NO;
}

+canonicalRequestForRequest:這個(gè)父類的抽象方法子類必須實(shí)現(xiàn)狡赐。

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}

以下是官方對(duì)這個(gè)方法的解釋窑业。當(dāng)我們想對(duì)某個(gè)請(qǐng)求添加請(qǐng)求頭或者返回新的請(qǐng)求時(shí),可以在這個(gè)方法里自定義然后返回枕屉,一般情況下直接返回參數(shù)里的NSURLRequest實(shí)例即可常柄。

It is up to each concrete protocol implementation to define what “canonical” means. A protocol should guarantee that the same input request always yields the same canonical form.

+requestIsCacheEquivalent:toRquest:這個(gè)方法能夠判斷當(dāng)攔截URL相同時(shí)是否使用緩存數(shù)據(jù),以下例子是直接返回父類實(shí)現(xiàn)搀擂。

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
    return [super requestIsCacheEquivalent:a toRequest:b];
}

-startLoading-stopLoading兩個(gè)方法分別告訴NSURLProtocol實(shí)現(xiàn)開(kāi)始和取消請(qǐng)求的處理西潘。

- (void)startLoading {
    NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];

    //打標(biāo)簽,防止無(wú)限循環(huán)
    [NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
    // dns解析
    NSMutableURLRequest *request = [self.class replaceHostInRequset:mutableReqeust];
    self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}

+ (NSMutableURLRequest *)replaceHostInRequset:(NSMutableURLRequest *)request {
    if ([request.URL host].length == 0) {
        return request;
    }

    NSString *originUrlString = [request.URL absoluteString];
    NSString *originHostString = [request.URL host];
    NSRange hostRange = [originUrlString rangeOfString:originHostString];
    if (hostRange.location == NSNotFound) {
        return request;
    }

    //用HappyDNS 替換host
    NSMutableArray *array = [NSMutableArray array];
    /// 第一dns解析為114哨颂,第二解析才是系統(tǒng)dns
    [array addObject:[[QNResolver alloc] initWithAddress:@"114.114.115.115"]];
    [array addObject:[QNResolver systemResolver]];
    QNDnsManager *dnsManager = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]];
    NSArray *queryArray = [dnsManager query:originHostString];
    if (queryArray && queryArray.count > 0) {
        NSString *ip = queryArray[0];
        if (ip && ip.length) {
            // 替換host
            NSString *urlString = [originUrlString stringByReplacingCharactersInRange:hostRange withString:ip];
            NSURL *url = [NSURL URLWithString:urlString];
            request.URL = url;

            [request setValue:originHostString forHTTPHeaderField:@"Host"];
        }
    }

    return request;
}
- (void)stopLoading {
    [self.connection cancel];
}

由于我們?cè)?code>-startLoading中新建了一個(gè)NSURLConnection實(shí)例喷市,因此要實(shí)現(xiàn)NSURLConnectionDelegate的委托方法。

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.client URLProtocolDidFinishLoading:self];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [self.client URLProtocol:self didFailWithError:error];
}

至此威恼,通過(guò)NSURLProtocol和QNDnsManager(七牛DNS解析開(kāi)源庫(kù))可以解決DNS劫持問(wèn)題品姓。但是NSURLProtocol還有更多的用途,以下是本文第二個(gè)內(nèi)容:webView上web請(qǐng)求的資源本地化箫措。

Web資源本地化

這里只舉一個(gè)簡(jiǎn)單的示例腹备,同樣是在上述NSURLProtocol的子類的-startLoading方法里

- (void)startLoading {
    NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
    // 處理MIME type
    NSString *mimeType = nil;
    mutableReqeust = [self.class replaceLocalSource:mutableReqeust];
    NSString *pathComponent = mutableReqeust.URL.absoluteString.lastPathComponent;
    if ([pathComponent hasSuffix:@"js"]) {
        mimeType = @"text/javascript";
    } else if ([pathComponent hasSuffix:@"css"]) {
        mimeType = @"text/css";
    }
    
    if (mimeType) {
        NSData *data = [NSData dataWithContentsOfFile:mutableReqeust.URL.absoluteString];
        
        NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[[self request] URL]
                                                            MIMEType:mimeType
                                               expectedContentLength:[data length]
                                                    textEncodingName:@"UTF8"];
        [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
        [[self client] URLProtocol:self didLoadData:data];
        [[self client] URLProtocolDidFinishLoading:self];
    }
}

#pragma mark - 判斷是否是本地資源
+ (BOOL)canReplaceLocalSource:(NSURLRequest *)request {
    NSString *absoluteString = request.URL.absoluteString;
    for (NSString *localSourceurl in [self localSourceArray]) {
        if ([absoluteString isEqualToString:localSourceurl]) {
            return YES;
        }
    }
    return NO;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市斤蔓,隨后出現(xiàn)的幾起案子植酥,更是在濱河造成了極大的恐慌,老刑警劉巖弦牡,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件友驮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡驾锰,警方通過(guò)查閱死者的電腦和手機(jī)卸留,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)椭豫,“玉大人耻瑟,你說(shuō)我怎么就攤上這事买喧。” “怎么了匆赃?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)今缚。 經(jīng)常有香客問(wèn)我算柳,道長(zhǎng),這世上最難降的妖魔是什么姓言? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任瞬项,我火速辦了婚禮,結(jié)果婚禮上何荚,老公的妹妹穿的比我還像新娘囱淋。我一直安慰自己,他們只是感情好餐塘,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布妥衣。 她就那樣靜靜地躺著,像睡著了一般戒傻。 火紅的嫁衣襯著肌膚如雪税手。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天需纳,我揣著相機(jī)與錄音芦倒,去河邊找鬼。 笑死不翩,一個(gè)胖子當(dāng)著我的面吹牛兵扬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播口蝠,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼器钟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了亚皂?” 一聲冷哼從身側(cè)響起俱箱,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎灭必,沒(méi)想到半個(gè)月后狞谱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡禁漓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年跟衅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片播歼。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伶跷,死狀恐怖掰读,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叭莫,我是刑警寧澤蹈集,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站雇初,受9級(jí)特大地震影響拢肆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜靖诗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一郭怪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧刊橘,春花似錦鄙才、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至绞愚,卻和暖如春叙甸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背位衩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工裆蒸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糖驴。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓僚祷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親贮缕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辙谜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • DNS 是什么 DNS (Domain Name System), 也叫網(wǎng)域名稱系統(tǒng)感昼,是互聯(lián)網(wǎng)的一項(xiàng)服務(wù)装哆。它實(shí)質(zhì)上...
    interstellar多米諾閱讀 2,814評(píng)論 0 6
  • 前言 DNS劫持指在劫持的網(wǎng)絡(luò)范圍內(nèi)攔截域名解析的請(qǐng)求,分析請(qǐng)求的域名定嗓,把審查范圍以外的請(qǐng)求放行蜕琴,否則返回假的IP...
    sindri的小巢閱讀 9,448評(píng)論 16 87
  • 1. 概述 在網(wǎng)絡(luò)環(huán)境中一般用戶只需要在瀏覽器中輸入url如www.sunny.com就可以到對(duì)應(yīng)服務(wù)器獲取相應(yīng)的...
    ghbsunny閱讀 2,901評(píng)論 0 7
  • ******科普片** 1、DNS劫持的危害 不知道大家有沒(méi)有發(fā)現(xiàn)這樣一個(gè)現(xiàn)象宵溅,在打開(kāi)一些網(wǎng)頁(yè)的時(shí)候會(huì)彈出一些與所...
    茉莉兒閱讀 31,296評(píng)論 84 217
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理凌简,服務(wù)發(fā)現(xiàn),斷路器恃逻,智...
    卡卡羅2017閱讀 134,713評(píng)論 18 139