网络安全-------防止被抓包
1.Ios应用网络安全之https
安全套接字层 (Secure Socket Layer, SSL) 是用来实现互联网安全通讯的最广泛的标准。Web 应用程序使用 HTTPS(基于 SSL 的 HTTP),HTTPS 使用数字证书来确保在服务器和客户端之间进行安全、加密的通讯。在 SSL 链接中,客户机和服务器在发送数据以前都要对数据进行加密,而后由接受方对其进行解密。html
当浏览器(客户端)须要与某个安全站点创建链接时,先创建TCP链接(三次握手),而后再发生 SSL会话握手:ios
浏览器将经过网络发送请求安全会话的消息(一般请求以 https 而非 http 开头的 URL)。web
服务器经过发送其证书(包括公钥)进行响应。数据库
浏览器将检验服务器的证书是否有效,并检验该证书是不是由其证书位于浏览器的数据库中的(而且是可信的)CA 所签发的。它还将检验 CA 证书是否已过时。后端
若是证书有效,浏览器将生成一个==一次性的、惟一的==会话密钥,并使用服务器的公钥对该会话密钥进行加密。而后,浏览器将把加密的会话密钥发送给服务器,这样服务器和浏览器都有一份会话密钥。浏览器
服务器可使用其专用密钥对消息进行解密,而后恢复会话密钥。缓存
握手以后,即表示客户端已验证了 Web 站点的身份,而且只有该客户端和 Web 服务器拥有会话密钥副本。从如今开始,客户机和服务器即可以使用该会话密钥对彼此间的全部通讯进行加密。这样就确保了客户机和服务器之间的通讯的安全性。安全
上面是通常也是应用最广泛的单向验证方式,由浏览器(客户端)来验证服务端的合法性;其实也能够作双向验证,服务器也能够验证浏览器(客户端)的合法性,不过通常使用在银行业务上,好比U盾之类。咱们如今关注广泛的单向验证方式的应用。服务器
2. iOS移动开发HTTPS应用现状
当下绝大部份的移动互联网项目都采用HTTP、HTTPS协议做为先后端的数据接口协议。而iOS开发群体中,绝大部分都在项目中应用了第三方开源的HTTP请求框架AFNetworking来快速而高效的开发,毕竟快鱼吃慢鱼的时代嘛。AFNetworking请求HTTP接口简直是简单得不能再简单了。只不过从iOS9.0开始须要设置Info.plist中App Transport Security打开非HTTP的资源加载,由于Apple默认只容许采用通过权威证书颁发机构签名的证书的HTTPS站点的访问,一切是为了安全。安全。安全。 那么咱们重点来分析采用HTTPS协议的后台接口的通常使用方式: HTTPS的服务器配置的证书分两大类,一类是通过权威机构签名颁发的证书,这样证书一般是要花钱买服务的,固然如今也有少数机构提供免费的证书签名服务。另外一类就是服务器配置的是研发人员本身签名生成的证书。网络
3.AFN调用使用权威机构颁发证书的HTTPS接口
如今AFNetworking框架已经修复了上半年爆出的SSL中间人攻击漏洞,并强烈要求开发者使用公钥绑定或者证书绑定的安全策略,那么正确使用AFNetworking请求这类证书的HTTPS站点代码很简单以下:
AFSecurityPolicy*policy=[AFSecurityPolicypolicyWithPinningMode:AFSSLPinningModePublicKey];policy.validatesDomainName=YES;AFHTTPSessionManager*manager=[AFHTTPSessionManagermanager];manager.securityPolicy=policy;manager.requestSerializer.cachePolicy=NSURLRequestReloadIgnoringLocalCacheData;
对于这类证书的站点,Info.plist都不须要设置,由于已是权威机构颁发的证书了,咱们只须要设置验证绑定方式和验证域名以防止中间人攻击,毕竟申请证书是花了钱(如今也有免费的申请,好比WoSign),省事一点。
4.AFN调用使用咱们本身签名证书的HTTPS接口
对于使用咱们本身签名的证书来讲,浏览器打开web站点也会默认阻止访问,除非用户手动把该站点加入信任列表,这个手动加入的过程其实就是不去验证服务器的合法性,任性的认为服务器是可信赖的。 那么手动加入信任列表,这样会致使证书的验证过程压根没发生,虽然能够成功访问目标服务器返回咱们须要的数据,其实,这中间颇有可能返回的数据不是正真的目标服务器返回的数据,也多是网络传输中间的第三者假装返回的数据。传输的数据被人窃取甚至纂改都是极可能的。
4.1 不正确的作法
浏览器手动加入自签名站点到信任列表这个操做的功能至关于iOS开发中AFNetworking的API的以下作法:
A 非权威机构颁发证书的HTTPS请求同样必须先在Info.plist设置以下:
NSAppTransportSecurityNSAllowsArbitraryLoads
B AFNetworking代码设置SecurityPolicy
站点https://tv.diveinedu.com是我前面博客所讲的配置方法配置的自签名证书。
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//容许非权威机构颁发的证书
manager.securityPolicy.allowInvalidCertificates = YES;
//也不验证域名一致性
manager.securityPolicy.validatesDomainName = NO;
//关闭缓存避免干扰测试
manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
[manager GET:@"https://tv.diveinedu.com/channel/" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@",error);
}];
通过如上两步设置以后,咱们能够在iOS应用中访问咱们采用自签名证书的HTTPS站点了。可是这个是不安全的,由于他在没有使用HTTPS/SSL代理和使用像Charles那样的HTTPS/SSL代理的状况下均可以访问服务器资源. 彻底能够说是白费功夫,只能防止“君子”在网络中用Wireshark之类来TCP抓包嗅探。由于毕竟仍是HTTPS加密了传输数据了。那为何我要说这样是白费功夫呢,由于这个办法不能防止中间人攻击!好比用户能够给手机设置HTTPS的SSL代理(好比Charles),彻底能够在代理中看到明文数据,因此,既然用了HTTPS就要防止中间人攻击,否则还不如不用HTTPS。
下面咱们来看看怎么用Charles代理抓包工具所抓到的HTTPS传输的数据:

上图是在Mac上运行Charles工具代理抓包,真机和Mac电脑同一个局域网,并设置代理为Mac机的IP和Charles的代理端口8888,而后启动App请求网络后抓到的数据。是否是很意外啊。HTTPS的数据也抓出明文了。 显然这样是很是不安全的,那么当咱们使用自签名证书的时候,咱们该如何来在App端(客户端)严格的验证服务器的合法性呢?
4.2 正确的作法
咱们要在App端严格验证服务器的合法性,防止网络中间的代理或者防火墙进行中间人的攻击和证书欺骗,那么咱们须要把服务器配置的证书打包到客户端程序中(私钥留服务器不要分发不用泄露,很是重要),在代码里去读取该证书/公钥信息和服务器返回的进行匹配验证. 在iOS开发中,从Xcode7和iOS9开始,Apple提高了App的网络安全性,App默认只能进行对采用权威机构签名颁发证书的Web站点进行访问(信任的HTTPS),而自签名的证书的HTTPS站点也被列为属于例外,因此咱们须要在App的Info.plist中单独为咱们的域名设置Exception Domains"白名单",而不是打开Allow Arbitrary Loads所有放开,设置信息以下:

NSAppTransportSecurityNSExceptionDomainstv.diveinedu.comNSExceptionAllowsInsecureHTTPLoads
这样就不像上面那个方法那样一刀切所有放开, 而是单独为某个域名放开设置.固然上面也可使用放开所有的设置NSAllowsArbitraryLoads为true.可是我建议使用白名单.
除此以外,要作到严格验证防止像Charles那样的中间人代理抓包,AFNetworking代码应该用以下设置:
//服务器端配置的包含公钥的证书分发到客户端后,须要转换为DER格式的证书文件.
//openssl x509 -outform der -in tv.diveinedu.com.crt -out tv.diveinedu.com.der
NSString *certFilePath = [[NSBundle mainBundle] pathForResource:@"tv.diveinedu.com" ofType:@"der"];
NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
NSSet *certSet = [NSSet setWithObject:certData];
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:certSet];
policy.allowInvalidCertificates = YES;
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy = policy;
//关闭缓存避免干扰测试
manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
[manager GET:@"https://tv.diveinedu.com/channel/" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@",error);
}];
上面的代码可以验证服务器身份在没有使用代理的时候能够正常访问服务器的资源,可是一旦用户给手机网络设置使用了如Charle那样的HTTPS/SSL代理服务,则会出现服务器证书验证失败,SSL网络链接会断开,老板不再用担忧数据接口被人抓包或者代理给扒出来了.故达到防止中间人攻击的效果.
当使用Charles SSL代理时Xcode调试终端出错信息图:

代理服务器Charles那边的出错信息图:

最后,关于iOS9和OSX 10.11 开发时,Xcode的Info.plist的NSAppTransportSecurity详细设置方法请参考Apple官方文档:NSAppTransportSecurity Reference
###欢迎更多开发者加qq 556120515 群进来交流