iOS WebView通讯链路安全

最近在整理技术点的时候发现电脑上存有一些知识点的记录,是之前在开发的过程当中遇到的一些问题,如今再从新梳理了出来web

项目需求:防止webview里面的数据被抓包,给app中的webview也加上https校验,防止攻击 https校验原理、加密原理、证书制做等已经有不少文章介绍,相信你们已经很熟悉了;本文只讲在多家服务器资源访问的状况下对web实现https校验的部分。objective-c

1、相关知识点

  1. 通常状况下不少公司对于ATS的web content设置都是打开了的,没有对证书进行校验,或者只是作了单向的证书校验,这样的话伪造一个假的有效证书web部分是很容易被别人抓到包的,此次要说的是web content设置为NO,而且是双向验证,采用的是证书锁定的校验模式,证书锁定须要客户端本地也存储一份证书,工做原理是首先会验证域名有效期等信息,其次会验证本地证书和服务器证书是否一致,一致则握手连接,不一致则断开连接,若是设置了代理而且即便配置了一个非当前公司服务器的有效证书也没法抓到数据,能够达到防止中间人攻击的效果。
  2. 无论上面app采用哪种校验方式,都是由服务器配置参数clientAuth来决定:
参数 描述
clientAuth=false 单向SSL验证
clientAuth=true 双向SSL验证
clientAuth=want 不强制验证客户端证书

2、实现过程

下面展现的是常规的web双向https校验安全

SecTrustResultType result;
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCerts);
OSStatus status = SecTrustEvaluate(serverTrust, &result);
 if (status == errSecSuccess &&
    (result == kSecTrustResultProceed ||
    result == kSecTrustResultUnspecified)) {
     NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
     completionHandler(NSURLSessionAuthChallengeUseCredential,card);
  } else {
      completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
  }

复制代码
  1. 以上就是常规的web实现https双向校验,可是运用到目前的项目一直校验失败;正常来讲当web经过https请求数据的时候,服务器会返回所有证书链,一个域名和一个证书是一一对应的,不能更改,而一个证书链里面又会包含有几级证书,根证书-二级证书-…..,目前咱们web请求返回的每一个证书链里面有3级证书;最后通过调试才发现某一个h5页面在加载的时候,返回了除了咱们公司本身的证书之外还返回了阿里云的证书(*.oss.aliyuncs.com),而且每一个h5界面返回的证书顺序还可能不同,返回的第一个证书链多是咱们公司本身的证书链,也多是oss阿里云的,顺序不必定,这就是问题所在,因此当前h5页面校验会失败没法正常打开。
  2. 更改思路,经过CFBridgingRelease(SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, 0)))取出服务器证书的概要信息,判断若是是当前本身公司域名下的证书,那么进行校验,不是好比oss阿里云的不校验,直接信任经过,通过测试无论本身服务器证书链在哪一个顺序或者有没有均可以正常显示,而且测试没法抓包:
    在这里插入图片描述
  3. 若是好比上面返回了oss.aliyun.com的证书,那么在plist中加上这个白名单就不会有阿里云的证书链返回了,就不须要进行校验,这样也是一种思路。

3、最终实现的代码以下

//从证书链中获取概要信息
    NSString *summary = CFBridgingRelease(SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, 0)));
    NSLog(@"当前请求证书概要=%@",summary);
    //获取信任管理对象,里面包含了待验证的证书,和自定义的策略
    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if ([summary containsString:@".xxxx.com"]) {
            NSString *path = [[NSBundle mainBundle] pathForResource:@"xxxx" ofType:@"der"];
            NSData *certData = [NSData dataWithContentsOfFile:path];
            //从der数据中建立证书对象
            NSMutableArray *pinnedCerts = [NSMutableArray arrayWithObjects:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData), nil];
            SecTrustResultType result;
            SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCerts);
            OSStatus status = SecTrustEvaluate(serverTrust, &result);
            if (status == errSecSuccess &&
                (result == kSecTrustResultProceed ||
                 result == kSecTrustResultUnspecified)) {
                    NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                    completionHandler(NSURLSessionAuthChallengeUseCredential,card);
                } else {
                    //中断本次连接
                    completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
                }
        }else {
            NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            completionHandler(NSURLSessionAuthChallengeUseCredential,card);
        }
    }else {
        NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, card);
    }

复制代码

4、拓展

1.通过测试对于设置了web的ATS=NO,plist是否加白名单状况: (1)加了白名单 不论是https仍是http均可以正常访问,因为设置了ATS=NO,必需校验,代理会收到校验的回调 (2)未加白名单 a、https能够访问,前提条件(1)这个域名服务器证书有效没有过时(2)webview的校验代理没有和本地证书匹配,直接经过,好比不是本身公司的域名访问 b、http没法正常访问服务器

2.除了web当时还考虑到图片的安全性问题;好比某个二维码支付界面或者好友头像,抓包工具中设置的其它有效证书那么也就能抓到图片,查看源码知道SDWebimage是不校验本地证书的,因此若是要考虑图片的安全性须要改这里的源码,和webview中校验的方法同样就能够了,原理相同。app

ps:除了以上校验客户端和服务端的证书所有信息之外,还能够经过 SecTrustCopyPublicKey(trust) 取出各自证书信息里面的公钥进行对比,也是能够达到一样的效果,这里就再也不细说了,感兴趣的同窗能够本身尝试一下。工具

相关文章
相关标签/搜索