一、引言
本篇博客主要讨论如何在客户端与服务端之间进行HTTPS网络传输,为了深入理解网络传输的基础原理,更加灵活的校验证书,博客的前半部分也将介绍一些HTTPS网络传输原理。当然,文章中有不正和疏漏之处,还望朋友不吝指正,感谢!
二、HTTP与HTTPS
我们都知道,HTTP是一种常用的网络传输协议,它是基于TCP的一种应用层协议,应用层是什么样的一个概念,通过下面这张示意图可以很好的理解:
HTTP协议的网络传输十分常见,例如网易的主页http://www.163.com/。HTTP类型的网络传输使用十分方便,但是其在安全性上却有很大问题,列举如下:
1.HTTP协议在传输数据时是明文的,任何人通过一个简单的抓包工具,就可以截获到所有传输数据。
2.HTTP协议在传输数据时无法保证数据的完整,在截获到明文数据后,很容易就可以将其篡改,这也是一些网页总是被植入恶意广告的原因。
3.HTTP协议在传输数据时无法保证真实性,这也是最恐怖的一点。误入了域名欺骗的钓鱼网站,极容易对用户带来财产损失。
基于上面3点安全性的考虑,一种更加安全的网络传输协议势必要推行,那就是HTTPS。
要理解HTTPS协议,首先需要明白什么是SSL/TLS。SSL全称“Secure Sockets Layer”,意思为安全套接层。其实由网景公司为了解决HTTP传输协议在安全方面的缺陷而设计的。后来被标准化,更名为TLS,全称“Transport Layer Security”,意思为传输层安全协议。
那么现在就好理解了,其实HTTPS就是将HTTP协议与TLS协议组合起来,在不改变HTTP协议原设计的基础上,为其添加安全性校验并对传输的数据进行加密。那么TLS究竟在网络传输的那一层进行了处理了,下图可以很好的表示:
三,https工作流程
1.Client发起一个HTTPS(比如https://juejin.im/user/5a9a9cdcf265da238b7d771c)的请求,根据RFC2818的规定,Client知道需要连接Server的443(默认)端口。
2.Server把事先配置好的公钥证书(public key certificate)返回给客户端。
3.Client验证公钥证书:比如是否在有效期内,证书的用途是不是匹配Client请求的站点,是不是在CRL吊销列表里面,它的上一级证书是否有效,这是一个递归的过程,直到验证到根证书(操作系统内置的Root证书或者Client内置的Root证书)。如果验证通过则继续,不通过则显示警告信息。
4.Client使用伪随机数生成器生成加密所使用的对称密钥,然后用证书的公钥加密这个对称密钥,发给Server。
5.Server使用自己的私钥(private key)解密这个消息,得到对称密钥。至此,Client和Server双方都持有了相同的对称密钥。
6.Server使用对称密钥加密“明文内容A”,发送给Client。
7.Client使用对称密钥解密响应的密文,得到“明文内容A”。
8.Client再次发起HTTPS的请求,使用对称密钥加密请求的“明文内容B”,然后Server使用对称密钥解密密文,得到“明文内容B”。
四,HTTP 与 HTTPS 的区别
- HTTP 是明文传输协议,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
关于安全性,用最简单的比喻形容两者的关系就是卡车运货,HTTP下的运货车是敞篷的,货物都是暴露的。而https则是封闭集装箱车,安全性自然提升不少。
- HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,谷歌、百度优先索引HTTPS网页;
- HTTPS需要用到SSL证书,而HTTP不用;
- HTTPS标准端口443,HTTP标准端口80;
- HTTPS基于传输层,HTTP基于应用层;
- HTTPS在浏览器显示绿色安全锁,HTTP没有显示;
五、CA证书的作用,形象解释
通过前面所介绍,我们知道HTTPS主要是为了解决3个问题:数据加密、数据完整、数据真实。那么下一步就是如何解决这些问题,数据加密在发送数据前依赖SSL层对数据进行加密,数据完整与真实性则要靠另一种关键技术:数字证书。
通过一个小例子可以很容易的理解证书的作用,这个例子的来源是<编程随想>的作者,我这里暂且借用一下:A公司的a到B公司办事,为了证明a确实是A公司的职员而不是商业间谍,A公司会为a提供一个带有公章的证明,当B公司看到这个证明时,就可以信任办事员a。对比网络传输,这个证明就是证书,证书可以保证这个网站的真实性。我们继续往后分析,当B公司与越来越多的公司进行商业合作时,就又有新的问题出现了,比如C公司的c来B公司办事,就需要拿C公司带公章的证明,D公司的d来B公司办事就需要拿D公司带公章的证明...这样一来,B公司要存放好多公司的公章和证明的模板,才能够完成校验。这样未免也太麻烦了,对应到网络传输中,客户端就是B公司,各个网站都有自己的证书文件,这样客户端需要安装信任大量的证书,为了解决这样的问题,就有了第三方CA机构。第三方CA机构是由大家公认信任的机构,例如R公司为第三方信任机构,其业务是为其他公司提供公章证明,这样一来,B公司只要保有这个R公司的公章证明副本,其他A,C,D公司的办事员也只需要从R公司申请到一个公章证明就可以到B公司来交流业务了。
CA的全称是“Certificate Authority”,意为证书授权中心。大部分CA机构颁发的证书都是需要付费的,CA机构颁发的证书一般都是根证书,根证书也比较容易理解,首先证书是有链式信任关系的,例如Y证书是由CA机构颁发的根证书,由这个Y证书还可以创建出许多子证书,子证书可以继续创建子证书,只要根证书是受信任的,其下所有的子证书都是受信任的,如下图:
我们可以打开开源中国博客的主页:https://www.oschina.net/blog。在Chrome浏览器地址栏左边可以查看证书信息,如下:
点击证书信息,可以看到完整的证书链,如下图:
从图中可以看到,根证书是由CA机构VerSign公司颁发的。此处还可以看到当前证书是否有效以及过期时间,如果证书无效则说明此网页信息有可能被篡改过,用户在访问时就要小心了。
除了CA机构可以签发证书外,个人其实也是可以创建证书的,当然个人创建的证书也是不被信任的,我们姑且把这类证书叫做自签名证书,如果用自签名证书搭建了HTTPS的服务,则客户端需要安装对应的证书信任,才可以进行此服务的访问。后面我们会进一步讨论自签名证书的使用。
六、搭建一个本地的HTTPS服务
使用Node.js可以快速的搭建前端服务,我们这里使借助Express框架来搭建本地的HTTPS服务,用于测试我们后边将要进行HTTPS通讯。Express搭建搭建项目模板的过程在以前的一篇博客中有详细的介绍,这里就不再重复了,地址如下:
使用Express搭建前端项目:https://my.oschina.net/u/2340880/blog/794928。
根据前面所述,搭建HTTPS服务需要有证书凭证,两种证书我们可以选择,一种是CA机构签发的证书,还有一种是我们自己制作的自签名证书,在Mac电脑上打开钥匙串访问应用,打开其中的证书助理,如下图所示:
选择其中的为您自己创建证书选项,如下图:
在之后的界面中,输入证书的名称,选择证书类型,如下图所示:
上面,我把证书的名字创建成了珲少,身份类型选择的是自签名的根证书,证书类型选择SSL服务器,之后点击创建即可完成证书的创建。
创建完成后,在钥匙串访问的登录证书中,可以看到已经有了珲少这个自签名的证书,如下图:
在证书上点击右键,选择导出选项,名字我将其取名为huishao,文件类型要选择.p12,如下图所示:
点击存储后,需要设置一个访问密码,这个密码将来将用于从.p12文件中获取证书和密钥,如下图所示:
之后,系统有可能会让你再次输入一个密码,将入下图所示,注意,这里需要输入的是系统的登录密码:
完成上面操作后,我们已经将一个.p12文件导出到了桌面。那么这个.p12文件到底是个什么东西呢,它和证书之间又有什么关系呢,其实.p12文件一个复合文件,其中包装了私钥与证书信息,使用OpenSSL工具可以将其中的信息进行提取,搭建一个HTTPS的服务器需要两个文件,分别问证书文件和私钥文件,下面我们来从.p12文件中提取这些需要的文件。
打开终端,cd到huishao.p12文件所在的目录下,使用如下命令可以将.p12文件中的私钥分解出来:
openssl pkcs12 -in huishao.p12 -nocerts -out privateKey.pem -nodes
之间会要求输入导出.p12文件时所设置的密码。
使用如下命令将.p12文件中的证书分解出来:
openssl pkcs12 -in huishao.p12 -nokeys -out cert.pem -nodes
之间也会要求输入导出.p12文件时所设置的密码。完成上面两部操作后,可以看到当前文件夹下多了两个文件,分别为cert.pem与privateKey.pem,他们分别是证书文件与密钥文件,将他们拷贝到Express项目的bin文件夹下,使得Express项目的结构看起来如下图所示:
下面我们来配置Express项目。
在生成好的Express项目中的www文件的末尾添加如下代码:
/*
HTTPS
*/
var fs = require('fs');
var https = require('https');
/*
密钥文件
*/
var privatekey = fs.readFileSync('./privateKey.pem', 'utf8');
/*
证书文件
*/
var certificate = fs.readFileSync('./cert.pem', 'utf8');
var options={key:privatekey, cert:certificate};
var serverHttps = https.createServer(options, app);
/*
绑定端口
*/
serverHttps.listen(8080,function () {
console.log('Https server listening on port ' + 8080);
});
用终端在bin文件夹下运行 node www,效果如下:
在浏览器打开:https://localhost:8080/users,如果服务器搭建成功,Chrome中会出现如下效果:
点击高级,点击其中的继续访问,可以正常获取到服务器返回的数据。到此,我们的HTTPS服务就搭建成功了。
六、iOS开发中通过配置info.plist文件来允许HTTP协议类型的通讯
前面扯了太多,终于提到重点部分了。Apple在iOS9中就已经漏出一些强制HTTPS通讯的端倪,只是给了开发者一些过渡,在iOS10及以后的审核机制中,Apple对于强制HTTPS的推动将会越来越强,如何让自己的应用程序尽快的适配HTTPS相关的标准,是iOS开发者必须面对的任务。
通过前面的分析我们了解,CA机构签发的证书是被默认信任的,这就是说,如果你的公司比较有钱,愿意花钱从CA机构申请一个付费的证书,那么很幸运,你的iOS工程是不需要做任何修改的,这些CA机构签发的证书是默认受信任的,因此你可以直接在程序中进行HTTPS类型的请求,所需要修改的只是将请求url改成https开头。但是另一种情况,无论出于什么原因,你的后台服务用的是自签名的证书,就想我们上面搭建的HTTPS服务一样,如果在不做任何处理的情况下在项目中访问这样的服务,就会出现问题了,原因是我们自己创建的自签名证书是不受信任的,系统默认拒绝了请求,示例如下:
-(void)normalHttps{
NSURLRequest * req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://localhost:8080/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}] resume];
}
运行工程后可以看到,并没有获取到相关数据,Xcode提示为:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
好了,那么我们先不管HTTPS的问题,如果我们直接对HTTP协议的服务进行请求,会不会有问题呢,将代码修改如下:
-(void)normalHttps{
NSURLRequest * req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:3000/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}] resume];
}
需要注意:Express在进行项目模板的创建时,会默认帮我们绑定一个3000端口的HTTP服务。
运行工程后,可以发现HTTP协议的请求也无法访问,报错如下:
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
其意思大致是说应用程序传输安全要求强制使用HTTPS类型的服务,但是开发者可以通过配置info.plsit文件来回避这一政策。这就是我们这节的重点,通过文件配置的方式来跳过应用安全传输协议。
在iOS9之后,开发者可以在Info.plist文件中添加如下键:NSAppTransportSecurity。这个键用来配置APP传输安全的相关策略,是字典类型,其中可以设置的键有五个,如下:
NSAllowsArbitraryLoads:布尔值,默认为NO,设置为YES则代表除了NSExceptionDomains中设置的域名外,其他所有请求的协议类型都不受限制,也就是说可以支持HTTP类型的请求,这个键的作用域是全局的,App内所有的请求都受影响,但是如果开发者设置为了YES,在提交审核时需要说明原因。
NSAllowsArbitraryLoadsForMedia:布尔值,默认为NO,设置为YES的话,则应用程序内所有的媒体数据的加载将不受协议类型的限制,同样如果开发者设置为了YES,则在提交审核时需要说明原因。
NSAllowsArbitraryLoadsInWebContent:布尔值,默认为NO。如果设置为YES,则应用程序内所有WebView的请求加载不受协议类型的限制,开发者设置为了YES,则在提交审核时需要说明原因。
NSAllowsLocalNetworking:布尔值,默认为NO,如果设置为YES,则在加载本地资源时不受安全传输协议的限制。
NSExceptionDomains:字典,其主要对某些特殊域名做限制。其中结构可以表示如下:
NSAppTransportSecurity : Dictionary {
NSAllowsArbitraryLoads : Boolean
NSAllowsArbitraryLoadsForMedia : Boolean
NSAllowsArbitraryLoadsInWebContent : Boolean
NSAllowsLocalNetworking : Boolean
//对某些域名做特殊限制
NSExceptionDomains : Dictionary {
: Dictionary {
NSIncludesSubdomains : Boolean
NSExceptionAllowsInsecureHTTPLoads : Boolean
NSExceptionMinimumTLSVersion : String
NSExceptionRequiresForwardSecrecy : Boolean // Default value is YES
NSRequiresCertificateTransparency : Boolean
}
}
}
NSIncludesSubdomains:布尔值,这个键的作用是设置此域名下的所有子域名是否采用和父域名相同的配置。
NSExceptionAllowsInsecureHTTPLoads:布尔值,设置是否允许此域名使用自签名的证书进行请求,默认为NO,如果设置为YES,则在提交时需要说明原因。
NSExceptionMinimumTLSVersion:设置所使用的TLS版本。
NSExceptionRequiresForwardSecret:设置为NO,则不允许向前加密方式。
NSRequiresCertificateTransparency:如果设置为YES,则服务端的证书要有有效的透明时间戳。
七、iOS中使用自签名的证书进行HTTPS请求校验
通过Info.plist文件我们是可以绕过安全传输协议的,但是不幸的是,从文档上看,无论开发者通过哪种方式来绕过安全传输协议,Apple都要求开发者在提审时提供合适的理由,这就是说:如果你使用了HTTP协议的请求,没有充足理由的话,你的App有很大的可能被审核拒绝。因此,更加保险的一种方式是将所有的服务都换成HTTPS协议的,如果有CA证书,当然完事大吉,如果没有,我们也可以通过验证自签名证书的方式来适配HTTPS协议。
在进行HTTPS请求时,服务端会先将证书文件返回给客户端,如果客户端的证书信任列表中包含这个证书,则此请求可以正常进行,如果没有,则请求会被拒绝。因此,在iOS中适配自签名证书的HTTPS请求实际上就是将这个自签名的证书安装进客户端的信任列表。iOS中需要使用的证书是der格式的,可以使用如下命令将pem格式的证书转换成der格式的证书:
openssl x509 -inform PEM -in cert.pem -outform DER -out cert.der
将生成的cert文件添加进工程中,修改请求如下:
-(void)normalHttps{
NSURLRequest * req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://localhost:8080/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionTask * task = [session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}];
[task resume];
}
除此之外,需要实现一个SURLSessionDelegate的协议方法如下:
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
NSLog(@"证书认证");
//先判断证书是否有效
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
//证书验证请求
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
/**
* 导入多张CA证书(Certification Authority,支持SSL证书以及自签名的CA)
*/
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"cert" ofType:@"der"];//自签名证书
NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
//可以添加多张证书
NSArray *caArray = @[caCert];
//验证规则
NSMutableArray *policies = [NSMutableArray array];
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
NSMutableArray *pinnedCertificates = [NSMutableArray array];
//进行自签名证书的添加
for (NSData *certificateData in caArray) {
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
SecTrustResultType result = -1;
//通过本地导入的证书来验证服务器的证书是否可信
SecTrustEvaluate(serverTrust, &result);
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
return [[challenge sender] useCredential: credential
forAuthenticationChallenge: challenge];
}
}
如上修改后,再次运行工程,可以看到已经成功请求到了HTTPS自签名证书服务提供的数据:
介于篇幅过长,关于NSURLAuthenticationChallenge相关类的更多探讨和常用网络库AFNetworking中HTTPS的适配,下篇博客会继续介绍。
八,CA证书与自签名证书的异同
如果你想要构建一个成功的网站,安全是关键因素之一,对于需要从访问者那里收集PIA(personally identifiable information,个人识别信息)的网站而言,尤其如此。
考虑一个需要输入社会保险号的网站,或更常见的,需要向其添加信用卡信息以完成购买行为的电子商务网站,在这样的网站上,安全不仅仅是来自那些访问者的期望,更是成功的关键。
如果你正在构建一个电子商务网站,首先就需要一个安全证书以便保证服务器的数据安全,对于证书的选择,即可以创建自签名证书,也可以从证书颁发机构(CA)获得由其签名的证书,让我们看看这两种证书的异同。
CA签名的证书和自签名证书的相似性
无论你的证书是由CA签名的,还是自己签名的,有一件事是完全相同的:你会得到一个安全的网站。通过HTTPS/SSL连接发送的数据将被加密,第三方无法窃听。
既然自签名证书也能做到这一点,那为何要向CA付款呢?
CA告诉你的客户:此服务器信息已由”信任源点“验证,最常用的CA是Verisign。CA会验证你的域名的所有权并颁发证书,这就能保证网站是安全而且合法的。
使用自签名证书的问题是,几乎每一个Web浏览器都会检查HTTPS连接是否由可信的CA签名,如果该连接是自签名的,则会将其标记为潜在风险并弹出错误消息,你的客户对该站点信任度就会降低。
简要总结:CA签名的证书兼具“身份证明”和“加密”双重功能,而由于自证身份不可信,自签名证书就只有加密功能,用于无需身份证明的场合。
在何种情况下可以使用自签名证书?
由于它们提供了相同的保护能力,所以能在任何使用CA签名证书的场合中使用自签名证书,但在某些场合特别适用自签名证书。例如,自签名证书非常适合测试HTTPS服务器,你不必仅仅为测试网站就要支付CA签名证书的费用,只需提醒测试人员他们的浏览器可能弹出警告信息。
也可以在需要输入隐私信息的情况下使用自签名证书,例如:
●用户名和密码表单
●收集个人(非财务)信息
当然,只有那些了解并信任你的人才会使用这样的网站。
所以你看到了,归根结底就是“信任”二字。当你使用自签名证书时,你是在对客户说:“请相信我——我就是我说的我”;当你使用由CA签名的证书时,你是在说:“请相信我——因为Verisign可以证明我的身份”。
如果你在做电子商务,就需要一个CA签名证书。
如果你使用自签名证书只是为了客户登录你的网站,那么他们可能会原谅你,但如果要求他们输入信用卡或Paypal的信息,那么你真的需要一个CA签名的证书,因为大多数人信任CA签名的证书,如果没有它,就不会通过HTTPS服务器做生意。所以如果你想在你的网站上卖东西,那就投资于证书吧,这只是做生意的成本。
有TrustAsia Technologies,Inc 的签发机构,就是
HTTPS请求
(1)证书转换
进到证书路径,执行openssl x509 -in 证书.crt -out 证书.cer -outform der
语句,这样就可以得到cer类型的证书了。双击,导入电脑。
(2)证书放入工程
a.可以直接把转换好的cer文件拖动到工程中。
b.可以在钥匙串内,找到你导入的证书,单击右键,导出项目,就可以导出.cer文件的证书了
(3)配置Info.plist
NSAppTransportSecurity
NSAllowsArbitraryLoads
(6)使用AFNetworking 3.x版本请求HTTPS
a.校验证书
// 初始化单例类
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy.SSLPinningMode = AFSSLPinningModeCertificate;
// 设置证书模式
NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"cer"];
NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:cerData, nil]];
// 客户端是否信任非法证书
mgr.securityPolicy.allowInvalidCertificates = YES;
// 是否在证书域字段中验证域名
[mgr.securityPolicy setValidatesDomainName:NO];
b.不校验证书
// 初始化单例类
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 设置非校验证书模式
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
manager.securityPolicy.allowInvalidCertificates = YES;
[manager.securityPolicy setValidatesDomainName:NO];
iOS开发中实现支持HTTPS,有两种方法:一是后台那边都处理好了,移动端直接可以使用HTTPS接口,二是后台给移动端一个服务器证书cer 文件,这时我们就需要将cer文件导入到我们的工程中,以下是实现方法
1. 双击证书,这时证书已经添加到了钥匙串中
2. 将cer 文件拖入工程中
3. 如果使用的是AFNetwotking 的话,在代码中添加以下代码
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//证书
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
manager.securityPolicy = securityPolicy;
// 2.设置证书模式
NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"tomcat" ofType:@"cer"]; //tomcat是cer文件的名称
NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:cerData, nil]];
// 客户端是否信任非法证书
manager.securityPolicy.allowInvalidCertificates = YES;
// 是否在证书域字段中验证域名
[manager.securityPolicy setValidatesDomainName:NO];
至此就已经完成支持HTTPS了
在一般的项目中,可以直接判断如果允许自签名证书的话,直接完全信任服务器证书,如果不允许自签名证书的话,直接拿本地的证书和服务器的证书比较
+ (void)setupFreshNetwork:(BOOL)allowInvalidCertificates{
AFHTTPSessionManager *sessionManager =[ [AFHTTPSessionManager alloc] init];
if (!allowInvalidCertificates) {
sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
sessionManager.securityPolicy.validatesDomainName = YES;
sessionManager.securityPolicy.allowInvalidCertificates = NO;
} else {
//是否允许无效证书(也就是自建的证书),默认为NO 如果是需要验证自建证书,需要设置为YES
sessionManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; //完全信任服务器证书;
sessionManager.securityPolicy.validatesDomainName = NO;
sessionManager.securityPolicy.allowInvalidCertificates = YES;
}
}
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
NSSet *defaultPinnedCertificates = [self certificatesInBundle:[NSBundle mainBundle]];
return [self policyWithPinningMode:pinningMode withPinnedCertificates:defaultPinnedCertificates];
}
这个函数自动在本地的目录查找.cer 文件