iOS https 证书信任漏洞解决办法
Xcode7版本开始默认使用https通讯协议,由于我在的公司从属金融行业,对通讯安全要求比较高,公司要求客户端在涉及敏感操作的接口使用https协议进行请求。
但是单纯使用https请求其实也是不安全的,至于为什么不安全请参考这篇文章:http://www.tuicool.com/articles/b2AnMv
(这篇文章里面有安卓如何解决这个漏洞,所以做安卓的有福了,代码直接可以贴过去用,但是iOS就没有这么幸运了)
所以公司要求我们把证书公钥写进客户端,这个公钥有俩作用,一是客户端每次与服务器通讯前,先比对服务器返回的公钥与客户端本地存的公钥是否一样,一样的话再继续与服务器通讯,不一样,就拒绝呗;二是客户端用公钥对数据进行加密,服务器端用私钥进行解密。这样,就能保证数据不会被抓包工具抓到啦。
但是对于我这样的小白来说,难度还是很大的。例如:怎么拿到.cer文件,怎么把.cer文件写入代码,怎么比对服务器给我返回的公钥与我存的公钥是否一致,用什么方法,在哪个环节对参数进行rsa加密。。。
我问了很多心目中的大神,还有本渣的同学。。。他们有些甚至完全不理解这个需求是什么意思。。。还有些已经不想再搭理总问白痴问题的本渣了。。。嘤嘤嘤嘤嘤~~所以我只能自己查资料了。
我冥思苦想了好久该怎么做还是毫无头绪,直到————接着往下看吧。
废话不多说了,我就从小白的角度说一下我是怎么完成这个艰巨任务的吧。
首先要声明一下我请求接口数据用的是第三方类:AFNetworking进行网络请求,以前不懂AFNetworking的强大,用到它的功能只是冰山一角,根本谈不上对这个第三方有什么理解,只是简单用一下它的post或get请求,这次通过使用它的https请求方法,又对它多了一点点了解。
第一步:对项目的.plist文件进行设置,具体内容如下
发现贴图片会比较坑,那我就贴代码吧,plist里面的代码复制出来成了介个样子:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>item 0</key>
<string>xxxx.xxxxxxx.com.cn</string>
<key>item 1</key>
<string>xxxx.xxxxxx.com</string>
<key>item 2</key>
<string>xxxx.xxxxx.com</string>
</dict>
</dict>
</plist>
我来解释一下这是在做什么:我做的这个项目不同的版块需要向不同的服务器请求数据,有的涉及敏感信息,必须使用https请求,其他的的一些无关紧要的,依然可以使用http请求。
所以,我的设置如下:
allow arbitrary loads 设置为yes 就是说我们这个app还是允许使用http请求的,相信大家都知道这个。
exception domains:例外的域名,也就是说,这个字典里设置的是必须使用https协议的域名。所以,就把需要进行https请求的域名添加进去咯。
这样设置以后,正好可以达到公司的要求:敏感操作的接口使用https请求,但是其他的可以使用http请求。好吧至少大部分满足了。
第二步:弄到.cer证书
比方说,你家服务器的域名是www.xxxxxx.com,那你就去IE浏览器访问https://www.xxxxxx.com这个网址,右键>>>属性>>>证书>>>详细信息>>>复制到文件,这样你就把证书下载到电脑里啦。(这个过程中可能会遇到“复制到文件”按钮不能点击的情况,可能是IE浏览器版本的问题,我使用的8.0.7601.17514版本是可以的~~)当然你有别的方法可以弄到这个.cer文件也是OK的。
第三步:把.cer证书导入工程。这一步很简单啦,跟导入别的文件一样的步骤。
第四步:代码部分:把.cer文件写入代码里面。
关键代码如下:
- (void)requestWithCerByManager:(AFHTTPRequestOperationManager *)manager {
NSString *cerPath= [[NSBundle mainBundle] pathForResource:@"www" ofType:@".cer"];
if (cerPath.length) {
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
[securityPolicy allowInvalidCertificates];
[securityPolicy setPinnedCertificates:@[certData]];
/**** SSL Pinning ****/
manager.securityPolicy = securityPolicy;
} else {
// do nothing
}
}
然后在请求数据的方法里,初始化manager之后,直接调用这个方法就好啦。
OK,这样基本上就可以啦~
另外用公钥(public key)对参数进行RSA加密的工作也不需要我们自己动手啦,af已经很贴心的帮我们完成了。
至于验证是否处理成功的方式嘛,可以两步进行:
第一步:查看经过处理的接口是否能够请求成功;
第二步:第一步OK的话,就对app进行抓包,看看能不能抓取到手机与服务器在相关接口通讯的数据。如果抓不到,那就是成功啦。
声明:
一、本人纯小白一枚,通过培训机构走出来的小渣渣,大学里学习的内容跟计算机和互联网八杆子打不着的文科生。如果哪些地方表现的比较外行,请勿喷哦。
二、本渣主要参考的资料来自:http://blog.cnbang.net/tech/2416/ 另外本渣把项目里的AFSecurityPolicy.m文件也替换成了这篇文章里的.m文件。
三、本渣的项目涉及多个域名,所以- (void)requestWithCerByManager:(AFHTTPRequestOperationManager *)manager这个方法里面要根据请求服务器的不同,写入不同的.cer文件哦,这里要提醒有相似需求的同学们注意一下啦。
OK, DONE;
从今以后本渣也是写过技术博客的人啦。
hia hia hia 飘走。
喝最烈的酒,看最美的风景。