最近在整顿技术点的时候发现电脑上存有一些知识点的记录,是以前在开发的过程中遇到的一些问题,当初再从新梳理了进去
我的项目需要:避免 webview 外面的数据被抓包,给 app 中的 webview 也加上 https 校验,避免攻打
https 校验原理、加密原理、证书制作等曾经有很多文章介绍,置信大家曾经很相熟了;本文只讲在多家服务器资源拜访的状况下对 web 实现 https 校验的局部。
一、相干知识点
- 个别状况下很多公司对于 ATS 的 web content 设置都是关上了的,没有对证书进行校验,或者只是做了单向的证书校验,这样的话伪造一个假的无效证书 web 局部是很容易被他人抓到包的,这次要说的是 web content 设置为 NO,并且是双向验证,采纳的是证书锁定的校验模式,证书锁定须要客户端本地也存储一份证书,工作原理是首先会验证域名有效期等信息,其次会验证本地证书和服务器证书是否统一,统一则握手链接,不统一则断开链接,如果设置了代理并且即便配置了一个非以后公司服务器的无效证书也无奈抓到数据,能够达到避免中间人攻打的成果。
- 不论下面 app 采纳哪一种校验形式,都是由服务器配置参数 clientAuth 来决定:
参数 | 形容 |
---|---|
clientAuth=false | 单向 SSL 验证 |
clientAuth=true | 双向 SSL 验证 |
clientAuth=want | 不强制验证客户端证书 |
二、实现过程
上面展现的是惯例的 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);
}
- 以上就是惯例的 web 实现 https 双向校验,然而使用到目前的我的项目始终校验失败;失常来说当 web 通过 https 申请数据的时候,服务器会返回全副证书链,一个域名和一个证书是一一对应的,不能更改,而一个证书链外面又会蕴含有几级证书,根证书 - 二级证书 -…..,目前咱们 web 申请返回的每个证书链外面有 3 级证书;最初通过调试才发现某一个 h5 页面在加载的时候,返回了除了咱们公司本人的证书以外还返回了阿里云的证书(*.oss.aliyuncs.com),并且每个 h5 界面返回的证书程序还可能不一样,返回的第一个证书链可能是咱们公司本人的证书链,也可能是 oss 阿里云的,程序不肯定,这就是问题所在,所以以后 h5 页面校验会失败无奈失常关上。
- 更改思路,通过 CFBridgingRelease(SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, 0)))取出服务器证书的概要信息,判断如果是以后本人公司域名下的证书,那么进行校验,不是比方 oss 阿里云的不校验,间接信赖通过,通过测试不论本人服务器证书链在哪个程序或者有没有都能够失常显示,并且测试无奈抓包:
- 如果比方下面返回了 oss.aliyun.com 的证书,那么在 plist 中加上这个白名单就不会有阿里云的证书链返回了,就不须要进行校验,这样也是一种思路。
三、最终实现的代码如下
// 从证书链中获取概要信息
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);
}
四、拓展
1. 通过测试对于设置了 web 的 ATS=NO,plist 是否加白名单状况:
(1)加了白名单
不论是 https 还是 http 都能够失常拜访,因为设置了 ATS=NO,必须校验,代理会收到校验的回调
(2)未加白名单
a、https 能够拜访,前提条件(1)这个域名服务器证书无效没有过期(2)webview 的校验代理没有和本地证书匹配,间接通过,比方不是本人公司的域名拜访
b、http 无奈失常拜访
2. 除了 web 过后还思考到图片的安全性问题;比方某个二维码领取界面或者好友头像,抓包工具中设置的其它无效证书那么也就能抓到图片,查看源码晓得 SDWebimage 是不校验本地证书的,所以如果要思考图片的安全性须要改这里的源码,和 webview 中校验的办法一样就能够了,原理雷同。
ps:除了以上校验客户端和服务端的证书全副信息以外,还能够通过 SecTrustCopyPublicKey(trust) 取出各自证书信息外面的公钥进行比照,也是能够达到同样的成果,这里就不再细说了,感兴趣的同学能够本人尝试一下。