iOS DNS劫持

作者: 小盟城主 | 来源:发表于2019-01-16 12:10 被阅读102次

    一、DNS

      DNSDomain Name System,域名系统),万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。
      简单说就是网络地址IP由数字组成的,例如百度的服务器地址是115.239.210.27,浏览器可以通过这个地址访问百度,但是这个数字记忆起来比较麻烦,于是就有了www.baidu.com这个更直观的表示方法,DNS就是连接这两者的服务。

    二、DNS解析

      域名到IP地址的映射,DNS解析请求采用UDP数据报且明文的。
      现在假如我们访问一个网站www.baidu.com从按下回车到百度页面显示到我们的电脑上会经历如下几个步骤:

    • 1:计算机会向我们的运营商(移动、电信、联通等)发出打开www.baidu.com的请求。
    • 2:运营商收到请求后会到自己的DNS服务器中找www.baidu.com这个域名所对应的服务器的IP地址(也就是百度的服务器的IP地址),这里比如是115.239.210.27
    • 3:运营商用第二步得到的IP地址去找到百度的服务器请求得到数据后返回给我们。

      其中第二步就是我们所说的DNS解析过程,域名和IP地址的关系其实就是我们的身份证号和姓名的关系,都是来标记一个人或者是一个网站的,只是IP地址/身份证号只是一串没有意义的数字,辨识度低,又不好记,所以就会在IP上加上一个域名以便区分,或是做的更加个性化,但是如果真的要来准确的区分还是要靠身份证号码或者是IP的,所以DNS解析就应运而生了。

    DNS解析

    二、DNS劫持

      DNS劫持,由于域名->IP这个过程中,其解析是基于UDP 协议实现,所以报文是明文状态,可能会在请求过程中被监测,然后攻击者做一些自己的处理,比如返回假的IP地址或者什么都不做使请求失去响应,其效果就是对特定的网络不能反应或访问的是假网址。根本原因就是以下两点:

    • 1:恶意攻击,拦截运营商的解析过程,把自己的非法东西嵌入其中。
    • 2:运营商为了利益或者一些其他的因素,允许一些第三方在自己的链接里打打广告之类的。
    DNS劫持

    四、防止DNS劫持

      了解了DNS劫持的相关资料后我们就知道了,防止DNS劫持就要从第二步入手,因为DNS解析过程是运营商来操作的,我们不能去干涉他们,不然我们也就成了劫持者了,所以我们要做的就是在我们请求之前对我们的请求链接做一些修改,将我们原本的请求链接www.baidu.com修改为115.239.210.27,然后请求出去,这样的话就运营商在拿到我们的请求后发现我们直接用的就是IP地址就会直接给我们放行,而不会去走他自己DNS解析了,也就是说我们把运营商要做的事情自己先做好了。不走他的DNS解析也就不会存在DNS被劫持的问题,从根本是解决了。

      我们知道要要把项目中请求的接口替换成IP其实很简单,URL是字符串,域名替换IP,无非就是一个字符串替换而已,的确这块其实没有什么技术含量。

      这里要说一下IP地址的来源,如何拿到一个域名所对应的IP呢?这里就是需要用到另一个服务——HTTPDNS

    1. HTTPDNS

      HTTPDNS是客户端基于http协议向服务器A发送域名B解析请求(例如:www.baidu.com),服务器A直接返回域名B对应的ip地址(例如:115.239.210.27),客户端获取到的IP后就向直接往此IP发送业务协议请求。
    这种方式替代了基于DNS协议向运营商LocalDNS发起解析请求,可以从根本上避免LocalDNS造成的域名劫持问题。
    常规的DNS解析是通过UDP方式。

      国内提供域名解析 API 接口的,有 DNSPod,现在国内有很多厂商为 DNSPod 开发了 SDK,比如 阿里、七牛(开源)等。不想自己写的,不妨使用这些 SDK。

    2. 内置IP列表
      可以在启动等阶段由服务端下发域名和 IP 的对应列表,客户端来进行缓存,发起网络请求的时候直接根据缓存 IP 来进行业务访问。

      实现 HTTP 协议下 IP 连接其实是很简单的,我们只需要通过 NSURLProtocol 来拦截网络请求,然后将符号条件的网络请求 URL 中的域名修改为 IP 就可以啦,也就是本地域名解析LocalDNS。

    #include <netdb.h>
    #include <arpa/inet.h>
    
    /**
     * 通过hostname获取ip列表 DNS解析地址
     */
    - (NSArray *)getDNSsWithDormain:(NSString *)hostName{
        NSMutableArray *result = [[NSMutableArray alloc] init];
        NSArray *IPV4DNSs = [self getIPV4DNSWithHostName:hostName];
        if (IPV4DNSs && IPV4DNSs.count > 0) {
            [result addObjectsFromArray:IPV4DNSs];
        }
        
        //由于在IPV6环境下不能用IPV4的地址进行连接监测
        //所以只返回IPV6的服务器DNS地址
        NSArray *IPV6DNSs = [self getIPV6DNSWithHostName:hostName];
        if (IPV6DNSs && IPV6DNSs.count > 0) {
            [result removeAllObjects];
            [result addObjectsFromArray:IPV6DNSs];
        }
        
        return [NSArray arrayWithArray:result];
    }
    
    //ipv4
    - (NSArray *)getIPV4DNSWithHostName:(NSString *)hostName
    {
        const char *hostN = [hostName UTF8String];
        struct hostent *phost;
        
        @try {
            phost = gethostbyname(hostN);
        } @catch (NSException *exception) {
            return nil;
        }
        
        NSMutableArray *result = [[NSMutableArray alloc] init];
        int j = 0;
        while (phost && phost->h_addr_list && phost->h_addr_list[j]) {
            struct in_addr ip_addr;
            memcpy(&ip_addr, phost->h_addr_list[j], 4);
            char ip[20] = {0};
            inet_ntop(AF_INET, &ip_addr, ip, sizeof(ip));
            
            NSString *strIPAddress = [NSString stringWithUTF8String:ip];
            [result addObject:strIPAddress];
            j++;
        }
        
        return [NSArray arrayWithArray:result];
    }
    
    //ipv6
    - (NSArray *)getIPV6DNSWithHostName:(NSString *)hostName
    {
        const char *hostN = [hostName UTF8String];
        struct hostent *phost;
        
        @try {
            /**
             * 只有在IPV6的网络下才会有返回值
             */
            phost = gethostbyname2(hostN, AF_INET6);
        } @catch (NSException *exception) {
            return nil;
        }
        
        NSMutableArray *result = [[NSMutableArray alloc] init];
        int j = 0;
        while (phost && phost->h_addr_list && phost->h_addr_list[j]) {
            struct in6_addr ip6_addr;
            memcpy(&ip6_addr, phost->h_addr_list[j], sizeof(struct in6_addr));
            NSString *strIPAddress = [self formatIPV6Address: ip6_addr];
            [result addObject:strIPAddress];
            j++;
        }
        
        return [NSArray arrayWithArray:result];
    }
    
    - (NSString *)formatIPV6Address:(struct in6_addr)ipv6Addr{
        NSString *address = nil;
        
        char dstStr[INET6_ADDRSTRLEN];
        char srcStr[INET6_ADDRSTRLEN];
        memcpy(srcStr, &ipv6Addr, sizeof(struct in6_addr));
        if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) != NULL){
            address = [NSString stringWithUTF8String:dstStr];
        }
        
        return address;
    }
    

    所以调用直接使用

    [self getDNSsWithDormain:@"www.baidu.com"];
    

    相关文章

      网友评论

        本文标题:iOS DNS劫持

        本文链接:https://www.haomeiwen.com/subject/djwydqtx.html