在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求。默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向Info.plist中添加NSAllowsArbitraryLoads设置绕过ATS(App Transport Security)的限制(否则须在应用审核时进行说明并很可能会被拒)。所以还未进行相应配置的公司需要尽快将升级为HTTPS的事项提上进程了。

本文将简述HTTPS及配置数字证书的原理并以配置实例和出现的问题进行说明,希望能对你提供帮助。(比心~)

HTTPS:

简单来说,HTTPS就是HTTP协议上再加一层加密处理的SSL协议,即HTTP安全版。相比HTTP,HTTPS可以保证内容在传输过程中不会被第三方查看、及时发现被第三方篡改的传输内容、防止身份冒充,从而更有效的保证网络数据的安全。

HTTPS客户端与服务器交互过程:

1、 客户端第一次请求时,服务器会返回一个包含公钥的数字证书给客户端;

2、 客户端生成对称加密密钥并用其得到的公钥对其加密后返回给服务器;

3、 服务器使用自己私钥对收到的加密数据解密,得到对称加密密钥并保存;

4、 然后双方通过对称加密的数据进行传输。

数字证书:

在HTTPS客户端与服务器第一次交互时,服务端返回给客户端的数字证书是让客户端验证这个数字证书是不是服务端的,证书所有者是不是该服务器,确保数据由正确的服务端发来,没有被第三方篡改。数字证书可以保证数字证书里的公钥确实是这个证书的所有者(Subject)的,或者证书可以用来确认对方身份。证书由公钥、证书主题(Subject)、数字签名(digital signature)等内容组成。其中数字签名就是证书的防伪标签,目前使用最广泛的SHA-RSA加密。

证书一般分为两种:

一种是向权威认证机构购买的证书,服务端使用该种证书时,因为苹果系统内置了其受信任的签名根证书,所以客户端不需额外的配置。为了证书安全,在证书发布机构公布证书时,证书的指纹算法都会加密后再和证书放到一起公布以防止他人伪造数字证书。而证书机构使用自己的私钥对其指纹算法加密,可以用内置在操作系统里的机构签名根证书来解密,以此保证证书的安全。

另一种是自己制作的证书,即自签名证书。好处是不需要花钱购买,但使用这种证书是不会受信任的,所以需要我们在代码中将该证书配置为信任证书。这就是本文的主要目的。

具体实现

我们在使用自签名证书来实现HTTPS请求时,因为不像机构颁发的证书一样其签名根证书在系统中已经内置了,所以我们需要在App中内置自己服务器的签名根证书来验证数字证书。

首先将服务端生成的.cer格式的根证书添加到项目中,注意在添加证书要一定要记得勾选要添加的targets。这里有个地方要注意:苹果的ATS要求服务端必须支持TLS 1.2或以上版本;必须使用支持前向保密的密码;证书必须使用SHA-256或者更好的签名hash算法来签名,如果证书无效,则会导致连接失败。由于我在生成的根证书时签名hash算法低于其要求,在配置完请求时一直报NSURLErrorServerCertificateUntrusted = -1202错误,希望大家可以注意到这一点。

本文使用AFNetworking 3.0来配置证书校验。其中AFSecurityPolicy类中封装了证书校验的过程。

AFSecurityPolicy分三种验证模式:

1、AFSSLPinningModeNone:只验证证书是否在新人列表中

2、AFSSLPinningModeCertificate:验证证书是否在信任列表中,然后再对比服务端证书和客户端证书是否一致

3、 AFSSLPinningModePublicKey:只验证服务端与客户端证书的公钥是否一致

这里我们选第二种模式,并且对AFSecurityPolicy的allowInvalidCertificates和 validatesDomainName进行设置。

AFSecurityPolicy具体配置代码如下:

AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

securityPolicy.allowInvalidCertificates = YES;      //是否允许使用自签名证书

securityPolicy.validatesDomainName = NO;           //是否需要验证域名

self.manager = [AFHTTPSessionManager manager];

self.manager.responseSerializer = [AFHTTPResponseSerializer serializer];

self.manager.securityPolicy = securityPolicy;

服务端在接收到客户端请求时会有的情况需要验证客户端证书,要求客户端提供合适的证书,再决定是否返回数据。这种情况即为质询(challenge)认证,双方进行公钥和私钥的验证。

为实现客户端验证,manager须设置需要身份验证回调的方法:

- (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block

并实现具体代码来替换AFNetworking的默认实现。其中参数challenge为身份验证质询,block返回对身份验证请求质询的配置。

在接受到质询后,客户端要根据服务端传来的challenge来生成所需的NSURLSessionAuthChallengeDisposition disposition和NSURLCredential *credential。disposition指定应对这个质询的方法,而credential是客户端生成的质询证书,注意只有challenge中认证方法为NSURLAuthenticationMethodServerTrust的时候,才需要生成挑战证书。最后回应服务器的质询。

具体实现代码如下:

[self.manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) {

// 获取服务器的trust object

SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];

//导入自签名证书

NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"cer"];

NSData* caCert = [NSData dataWithContentsOfFile:cerPath];

NSArray *cerArray = @[caCert];

weakSelf.manager.securityPolicy.pinnedCertificates = cerArray;

SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);

NSCAssert(caRef != nil, @"caRef is nil");

NSArray *caArray = @[(__bridge id)(caRef)];

NSCAssert(caArray != nil, @"caArray is nil");

OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);

SecTrustSetAnchorCertificatesOnly(serverTrust,NO);

NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");

//选择质询认证的处理方式

NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;

__autoreleasing NSURLCredential *credential = nil;

//NSURLAuthenticationMethodServerTrust质询认证方式

if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

//基于客户端的安全策略来决定是否信任该服务器,不信任则不响应质询 。

if ([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {

//创建质询证书

credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

//确认质询方式

if (credential) {

disposition = NSURLSessionAuthChallengeUseCredential;

} else {

disposition = NSURLSessionAuthChallengePerformDefaultHandling;

}

} else {

//取消质询

disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;

}

} else {

disposition = NSURLSessionAuthChallengePerformDefaultHandling;

}

return disposition;

}];

详细代码发布在了github上,使用时请注意在ViewController和NetworkManager中#Warning的提示,将证书拖入项目并在NetworkManager中添加证书名称,在ViewController添加自己的URL。

文章中如有错误和疏漏,欢迎留言指教讨论。

参考文章:

  • Certificate, Key, and Trust Services Tasks for iOS

    http://t.cn/RIieZFE

  • 关于 iOS 10 中 ATS 的问题

    http://t.cn/R5SFNd2

  • App Transport Security(ATS)

    http://southpeak.github.io/2015/09/14/app-transport-security-ats/

  • 数字证书原理

    http://www.cnblogs.com/JeffreySun/archive/2010/06/24/1627247.html

  • iOS使用自签名证书实现HTTPS请求

    http://www.jianshu.com/p/e6a26ecd84aa

iOS 用自签名证书实现 HTTPS 请求的原理实例讲解相关推荐

  1. iOS 用自签名证书实现 HTTPS 请求的原理

    在16年的WWDC中,Apple已表示将从2017年1月1日起,所有新提交的App必须强制性应用HTTPS协议来进行网络请求.默认情况下非HTTPS的网络访问是禁止的并且不能再通过简单粗暴的向Info ...

  2. iOS使用自签名证书实现HTTPS请求

    原文链接:http://www.jianshu.com/p/e6a26ecd84aa 由于苹果规定2017年1月1日以后,所有APP都要使用HTTPS进行网络请求,否则无法上架,因此研究了一下在iOS ...

  3. python 证书-Python 发送带自签名证书的 https 请求

    在拥有 .pfx 文件和其密码(若有加密)的前提下进行 https 请求 (关于这些文件的说明,参考:https://blog.51cto.com/wushank/1915795): 所有方法均忽略了 ...

  4. 关于IOS由于Dropbox被封,https请求不好用的解决办法

    最近研究IOS的In-House安装方法,好不容易申请下来了企业级证书,也使用了Dropbox的网盘来支持苹果的In-House安装方法,也给客户展示了,下载的地址也给客户了.没过几天,坑爹的天朝把D ...

  5. Nginx通过OpenSSL创建自签名证书配置HTTPS及二级目录

    目录 配置Https Nginx配置二级目录 升级示例 部署HTTP 升级为HTTPS 配置Https Nginx通过OpenSSL配置Https及二级虚拟目录 1.创建私钥秘钥和证书 mkdir - ...

  6. pythonrequests请求https错误_如何解决python之requests安全证书(HTTPS请求)问题?

    用requests包请求https的网站时,我们偶尔会遇到证书问题.也就是常见的SSLerror,遇到这种问题莫慌莫慌. 这里没有找到合适的网站去报SSL证书的错误,所以就假装请求了一个https的网 ...

  7. 免费SSL证书实现https请求

    文章目录 前言 证书申请 资料完善 域名申请 域名证书申请验证(二选一) 手动DNS配置方式(推荐) 本地文件验证(麻烦,不建议,用上面推荐的方式即可) 证书配置 测试 https测试 nginx如何 ...

  8. tomcat使用自签名证书实现https加密访问

    部署好java环境和tomcat之后 执行以下语句 #生成证书,keytool是java工具命令,-genkey生成证书,-alias证书名称,-keyalg应该是指算法,-keystore是证书存储 ...

  9. 内网使用openssl自签名证书开启https连接,同时解决chrome浏览器中的不安全访问

    1.在内网中开启https访问,使用ip,请直接看第二步.如果是外网域名的话,建议直接去从 阿里云或者其他的网站中直接用权威机构颁发的证书.地址 2.请先安装OpenSSL  3.生成证书 创建根证书 ...

最新文章

  1. python秒表游戏_数学游戏Tkinter中的Python计时器
  2. 深度学习之TensorFlow
  3. LeetCode 542. 01 Matrix
  4. ImportError: No Module Named [x]
  5. 微信客户管理SCRM系统SDK
  6. kux转mp4_QSV、KUX一秒转换成MP4,这两款神器你还不收藏?
  7. 使用Selenium对QQ邮箱登录页面进行自动化测试
  8. 基于C语言制作的超级玛丽小游戏
  9. 用python制作电子时钟包装_使用电子水墨屏和树莓派制作的时钟,Epaper_clock
  10. 英文 E-mail写作指南
  11. LE MAX2 X820刷机记
  12. 【帆软报表】使用技巧及常见问题汇总-持续更新
  13. 洛谷 P3159(BZOJ 2668)[CQOI2012]交换棋子
  14. JavaScript EventListener
  15. 社区发现算法原理与louvain源码解析
  16. flink故障恢复的流程(从检查点恢复状态)
  17. Android逆向工程-破解 哈皮妹-萝莉
  18. OSDI 2021 VEGITO 论文阅读
  19. Oracle ClusterwarePRCT-1011 : Failed to run oifcfg. Detailed error: null
  20. 【观察】智能决策:从中国制造到中国智造的通关“金钥匙”

热门文章

  1. netty集成ssl完整参考指南(含完整源码)
  2. 【MongoDB学习之一】初始MongoDB
  3. Codeforces Round #372 (Div. 2), problem: (B) Complete the Word
  4. 【VS开发】【智能语音处理】Windows下麦克风语音采集
  5. UICollectionView之网络图片解析
  6. 报表性能优化方案之报表服务器优化基础讲解
  7. Android基础知识之Manifest文件的组织结构
  8. MFC最小化到系统托盘
  9. expires与etag控制页面缓存的优先级
  10. Linux动态库和静态库比较