基于AFNetWorking 和 alamofire 的SSL特定服务器证书信任处理

2023-10-22 19:10

本文主要是介绍基于AFNetWorking 和 alamofire 的SSL特定服务器证书信任处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

swift alamofire 针对自签名的证书。在发送网络的请求的时候去信任签名证书


首先来分析一下什么是HTTPS以及了解HTTPS对于iOS开发者的意义

HTTPS 以及SSL/TSL

  • 什么是SSL?

SSL(Secure Sockets Layer, 安全套接字层),因为原先互联网上使用的 HTTP 协议是明文的,存在很多缺点,比如传输内容会被偷窥(嗅探)和篡改。 SSL 协议的作用就是在传输层对网络连接进行加密。

  • 何为TLS?

到了1999年,SSL 因为应用广泛,已经成为互联网上的事实标准。IETF 就在那年把 SSL 标准化。标准化之后的名称改为 TLS(Transport Layer Security,传输层安全协议)。SSL与TLS可以视作同一个东西的不同阶段

  • HTTPS

简单来说,HTTPS = HTTP + SSL/TLS, 也就是 HTTP over SSL 或 HTTP over TLS,这是后面加 S 的由来 。

HTTPS和HTTP异同:HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。HTTP的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。

在WWDC 2016开发者大会上,苹果宣布了一个最后期限:到2017年1月1日 App Store中的所有应用都必须启用 App Transport Security安全功能。App Transport Security(ATS)是苹果在iOS 9中引入的一项隐私保护功能,屏蔽明文HTTP资源加载,连接必须经过更安全的HTTPS。苹果目前允许开发者暂时关闭ATS,可以继续使用HTTP连接,但到年底所有官方商店的应用都必须强制性使用ATS。

所以对于iOS开发者来说,需要尽早解决HTTPS请求的问题。

发送HTTPS请求信任SSL证书和自签名证书,分为三种情况

1.如果你的app服务端安装的是SLL颁发的CA,可以使用系统方法直接实现信任SSL证书,关于Apple对SSL证书的要求请参考:苹果官方文档CertKeyTrustProgGuide

这种方式不需要在Bundle中引入CA文件,可以交给系统去判断服务器端的证书是不是SSL证书,验证过程也不需要我们去具体实现。

示例代码:

NSURL *URL = [NSURL URLWithString:URLString];NSURLRequest *request = [[NSURLRequest alloc] initWithURL:URL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];//创建同步连接NSError *error = nil;NSData *receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];NSString *receivedInfo = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];

当然,如果你需要同时信任SSL证书和自签名证书的话还是需要在代码中实现CA的验证,这种情况在后面会提到。



文/无忌不悔(简书作者)
原文链接:http://www.jianshu.com/p/6b9c8bd5005a
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

AFNetWorking


2.基于AFNetWorking的SSL特定服务器证书信任处理,重写AFNetWorking的customSecurityPolicy方法,这里我创建了一个HttpRequest类,分别对GET和POST方法进行了封装,以GET方法为例:

+ (void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure {// 1.获得请求管理者AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];// 2.申明返回的结果是text/html类型mgr.responseSerializer = [AFHTTPResponseSerializer serializer];// 3.设置超时时间为10smgr.requestSerializer.timeoutInterval = 10;// 加上这行代码,https ssl 验证。if(openHttpsSSL) {[mgr setSecurityPolicy:[self customSecurityPolicy]];}// 4.发送GET请求[mgr GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObj){if (success) {success(responseObj);}} failure:^(AFHTTPRequestOperation *operation, NSError *error) {if (error) {failure(error);}}];
}
+ (AFSecurityPolicy*)customSecurityPolicy {// /先导入证书NSString *cerPath = [[NSBundle mainBundle] pathForResource:certificate ofType:@"cer"];//证书的路径NSData *certData = [NSData dataWithContentsOfFile:cerPath];// AFSSLPinningModeCertificate 使用证书验证模式AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];// allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO// 如果是需要验证自建证书,需要设置为YESsecurityPolicy.allowInvalidCertificates = YES;//validatesDomainName 是否需要验证域名,默认为YES;//假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。//置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。//如置为NO,建议自己添加对应域名的校验逻辑。securityPolicy.validatesDomainName = NO;securityPolicy.pinnedCertificates = @[certData];return securityPolicy;
}

其中的cerPath就是app bundle中证书路径,certificate为证书名称的宏,仅支持cer格式,securityPolicy的相关配置尤为重要,请仔细阅读customSecurityPolicy方法并根据实际情况设置其属性。

这样,就能够在AFNetWorking的基础上使用HTTPS协议访问特定服务器,但是不能信任根证书的CA文件,因此这种方式存在风险,读取pinnedCertificates中的证书数组的时候有可能失败,如果证书不符合,certData就会为nil。

3.更改系统方法,发送异步NSURLConnection请求。

- (void)getDataWithURLRequest {//connectionNSString *urlStr = @"https://developer.apple.com/cn/";NSURL *url = [NSURL URLWithString:urlStr];NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];[connection start];
}

重点在于处理NSURLConnection的didReceiveAuthenticationChallenge代理方法,对CA文件进行验证,并建立信任连接。

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {/*//直接验证服务器是否被认证(serverTrust),这种方式直接忽略证书验证,直接建立连接,但不能过滤其它URL连接,可以理解为一种折衷的处理方式,实际上并不安全,因此不推荐。SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];return [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]forAuthenticationChallenge: challenge];*/if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {do{SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];NSCAssert(serverTrust != nil, @"serverTrust is nil");if(nil == serverTrust)break; /* failed *//***  导入多张CA证书(Certification Authority,支持SSL证书以及自签名的CA)*/NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"cloudwin" ofType:@"cer"];//自签名证书NSData* caCert = [NSData dataWithContentsOfFile:cerPath];NSString *cerPath2 = [[NSBundle mainBundle] pathForResource:@"apple" ofType:@"cer"];//SSL证书NSData * caCert2 = [NSData dataWithContentsOfFile:cerPath2];NSCAssert(caCert != nil, @"caCert is nil");if(nil == caCert)break; /* failed */NSCAssert(caCert2 != nil, @"caCert2 is nil");if (nil == caCert2) {break;}SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);NSCAssert(caRef != nil, @"caRef is nil");if(nil == caRef)break; /* failed */SecCertificateRef caRef2 = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert2);NSCAssert(caRef2 != nil, @"caRef2 is nil");if(nil == caRef2)break; /* failed */NSArray *caArray = @[(__bridge id)(caRef),(__bridge id)(caRef2)];NSCAssert(caArray != nil, @"caArray is nil");if(nil == caArray)break; /* failed */OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");if(!(errSecSuccess == status))break; /* failed */SecTrustResultType result = -1;status = SecTrustEvaluate(serverTrust, &result);if(!(errSecSuccess == status))break; /* failed */NSLog(@"stutas:%d",(int)status);NSLog(@"Result: %d", result);BOOL allowConnect = (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed);if (allowConnect) {NSLog(@"success");}else {NSLog(@"error");}/* https://developer.apple.com/library/ios/technotes/tn2232/_index.html *//* https://developer.apple.com/library/mac/qa/qa1360/_index.html *//* kSecTrustResultUnspecified and kSecTrustResultProceed are success */if(! allowConnect){break; /* failed */}#if 0/* Treat kSecTrustResultConfirm and kSecTrustResultRecoverableTrustFailure as success *//*   since the user will likely tap-through to see the dancing bunnies */if(result == kSecTrustResultDeny || result == kSecTrustResultFatalTrustFailure || result == kSecTrustResultOtherError)break; /* failed to trust cert (good in this case) */
#endif// The only good exit pointreturn [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]forAuthenticationChallenge: challenge];} while(0);}// Bad dogreturn [[challenge sender] cancelAuthenticationChallenge: challenge];}

这里的关键在于result参数的值,根据官方文档的说明,判断(result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed)的值,若为1,则该网站的CA被app信任成功,可以建立数据连接,这意味着所有由该CA签发的各个服务器证书都被信任,而访问其它没有被信任的任何网站都会连接失败。该CA文件既可以是SLL也可以是自签名。

NSURLConnection的其它代理方法实现

#pragma mark -- connect的异步代理方法
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {NSLog(@"请求被响应");_mData = [[NSMutableData alloc]init];
}-(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {NSLog(@"开始返回数据片段");[_mData appendData:data];
}-(void)connectionDidFinishLoading:(NSURLConnection *)connection {NSLog(@"链接完成");//可以在此解析数据NSString *receiveInfo = [NSJSONSerialization JSONObjectWithData:self.mData options:NSJSONReadingAllowFragments error:nil];NSLog(@"received data:\\\\n%@",self.mData);NSLog(@"received info:\\\\n%@",receiveInfo);
}//链接出错
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {NSLog(@"error - %@",error);
}

至此,HTTPS信任证书的问题得以解决,这不仅是为了响应Apple强制性使用ATS的要求,也是为了实际生产环境安全性的考虑,HTTPS是未来的趋势,建议尽早支持。



原文链接:http://www.jianshu.com/p/6b9c8bd5005a


这篇关于基于AFNetWorking 和 alamofire 的SSL特定服务器证书信任处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/263096

相关文章

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

Thymeleaf:生成静态文件及异常处理java.lang.NoClassDefFoundError: ognl/PropertyAccessor

我们需要引入包: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>sp

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“

速盾:直播 cdn 服务器带宽?

在当今数字化时代,直播已经成为了一种非常流行的娱乐和商业活动形式。为了确保直播的流畅性和高质量,直播平台通常会使用 CDN(Content Delivery Network,内容分发网络)服务器来分发直播流。而 CDN 服务器的带宽则是影响直播质量的一个重要因素。下面我们就来探讨一下速盾视角下的直播 CDN 服务器带宽问题。 一、直播对带宽的需求 高清视频流 直播通常需要传输高清视频

jenkins 插件执行shell命令时,提示“Command not found”处理方法

首先提示找不到“Command not found,可能我们第一反应是查看目标机器是否已支持该命令,不过如果相信能找到这里来的朋友估计遇到的跟我一样,其实目标机器是没有问题的通过一些远程工具执行shell命令是可以执行。奇怪的就是通过jenkinsSSH插件无法执行,经一番折腾各种搜索发现是jenkins没有加载/etc/profile导致。 【解决办法】: 需要在jenkins调用shell脚

Jenkins 插件 地址证书报错问题解决思路

问题提示摘要: SunCertPathBuilderException: unable to find valid certification path to requested target...... 网上很多的解决方式是更新站点的地址,我这里修改了一个日本的地址(清华镜像也好),其实发现是解决不了上述的报错问题的,其实,最终拉去插件的时候,会提示证书的问题,几经周折找到了其中一遍博文