大家好,今天小编来为大家解答深入解析iOS平台HTTPS证书链验证机制这个问题,很多人还不知道,现在让我们一起来看看吧!
对称加密只有一把密钥,既用于加密又用于解密;
非对称加密有公钥和私钥。只有公钥才能解密私钥加密的内容。只有私钥才能解密公钥加密的内容。
为了提高安全性,我们常用的做法是使用对称加密来加密数据。但是,如果仅使用对称加密,则在双方通信开始时密钥将始终以明文形式传输。所以密钥从一开始就已经泄露了,根本没有安全可言。因此,TLS/SSL在握手阶段结合了非对称加密,保证只有通信双方知道对称加密密钥。大致流程如下:
TSL:SSL_handshake.png
因此,HTTPS传输安全的关键是保证在TLS/SSL握手阶段只有通信双方才能得到Session Key!
数字证书的内容
X.509应该是目前比较流行的SSL数字证书标准,包括(但不限于)以下字段:
字段值说明
主题名称:用于识别数字证书的信息
Common Name:对于客户端证书,通常是对应的域名
证书颁发者(颁发者名称) 有关颁发和签署证书的实体的信息
签名算法用于签名的算法
序列号(Serial Number) 由数字证书颁发机构(CA) 赋予证书的唯一整数。数字证书有一个序列号。
之前无效(´)
(口)(—之后无效
公钥公钥
签名是通过签名算法计算出证书内容后得到的数据,用于验证证书是否被篡改。
除了上面列出的字段外,还有很多扩展字段,这里不再详述。
下图是维基百科的公钥证书:
wikipedia_cer.png
数字证书的生成和验证
数字证书的生成是分层的,下层证书需要上层证书的私钥签名。
因此,后者是前者的证书颁发者,也就是说,上级证书的Subject Name 就是其下级证书的Issuer Name。
证书颁发者从证书申请者那里获得一些必要的信息(对象名称、公钥和私钥)后,通过SHA-256哈希得到证书内容的摘要,然后用自己的私钥对摘要进行加密,得到数字证书。签名。根据现有信息,生成包含公钥和私钥的两个证书。
此时,有几个问题:
问:如果颁发数字证书必须用上级证书的私钥加密,那么顶级证书——根证书来自哪里?
根证书是自签名的,即用自己的私钥进行签名,不需要另一个证书的私钥来生成签名。
问:如何验证证书是否被篡改?
当客户端通过HTTPS访问站点时,服务器返回整个证书链。下图的证书链就是一个例子:
chain_hierarchy.png
为了验证*.wikipedia.org证书没有被篡改,我们需要使用GlobalSign组织验证CA提供的公钥-SHA256-G2解密前者的签名并获得摘要Digest1。我们的客户还计算了前一个证书的内容并获得摘要。摘要2.比较两个摘要就可以知道前者是否被篡改。后者是一样的,使用GlobalSign Root CA提供的公钥验证。当验证受信任的根证书时,可以确定证书*.wikipedia.org 是受信任的。
问:为什么上述根证书GlobalSign Root CA 受信任?
由数字证书颁发机构(Certificate Authority,CA)签名和管理的CA根证书将被包含在您的浏览器和操作系统的可信证书列表中,并且该列表将用于确定根证书是否可信。所以不要随便将奇怪的根证书导入到你的操作系统中。
问:生成的数字证书(例如*.wikipedia.org)可以用来签署新证书吗?
不确定。如下图,扩展字段中有一个名为Basic Constraints的数据结构。有一个字段叫做Path Length Constraint,它表示证书可以继续签署CA子证书的深度。这里是0,表示这个GlobalSign组织验证CA-SHA256-G2只能签署客户端证书,并且客户端证书不能用于签署新证书,只有CA子证书可以这样做。
路径长度约束.png
iOS 上的证书链验证
正确覆盖TLS 链验证中提到:
验证TLS 证书后,操作系统会验证其信任链。如果该信任链仅包含有效证书并以已知(受信任)锚证书结束,则该证书被视为有效。
所以在iOS中,证书是否有效的标准是:
如果信任链仅包含有效证书并以可信锚结尾,则证书被视为有效。
可信锚点是指系统隐式信任的证书,通常是系统包含的CA根证书。但是,您也可以在验证证书链时将自定义证书设置为可信锚点。
NSURLSession 实现HTTPS
具体来说,当使用NSURLSession 通过HTTPS 访问网站时,-URLSession:didReceiveChallenge:completionHandler: 回调中会收到一个质询,需要您提供身份验证信息才能完成连接。这时,我们可以使用challenge.protectionSpace.authenticationMethod来获取保护空间需要我们认证的方法。如果这个值为NSURLAuthenticationMethodServerTrust,我们就可以干预TLS握手中的“验证数字证书的有效性”步骤。
默认实现
系统默认的实现(即代理不实现该方法)就是验证这条信任链。如果结果有效,将基于serverTrust 创建凭证,以与服务器建立SSL 连接。否则,您将收到类似“该服务器的证书无效.”的错误,并且无法访问它。
比如访问https://www.google.com时,我们不实现这个方法仍然可以访问成功。系统验证Google服务器返回的从叶节点证书到根证书的证书链(有效期、签名等)。当遇到根证书时,发现它作为可信锚点存在于可信证书列表中。然后验证通过并允许建立与服务器的连接。
谷歌.png
当我们访问https://www.12306.cn时,“该服务器的证书无效”。您可能正在连接到冒充“www.12306.cn”的服务器,这可能会使您的机密信息面临风险。错误。原因是系统验证根证书时发现它是自签名且不可信的。
12306.png
定制实施
如果我们要实现这个代理方法,我们需要向completionHandler块提供NSURLSessionAuthChallengeDisposition(处置方法)和NSURLCredential(资格认证)两个参数:
复制代码
1 -(void)URLSession:(NSURLSession *)会话
2 didReceiveChallenge:(NSURLAuthenticationChallenge *)挑战
3 完成处理程序:(无效(^)(NSURLSessionAuthChallengeDisposition,
4 NSURLCredential * _Nullable))completionHandler {
5
6 //如果使用默认的处理方法,凭证将被忽略
7 NSURLSessionAuthChallengeDisposition 配置=NSURLSessionAuthChallengePerformDefaultHandling;
8 NSURLCredential凭证=nil;
9
10 if ([challenge.protectionSpace.authenticationMethod]
11 等于字符串:
12 NSURLAuthenticationMethodServerTrust]){
13
14/调用自定义验证流程/
15 if ([self myCustomValidation:challenge]) {
16 凭证=[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
17 if(凭证){
18 处置=NSURLSessionAuthChallengeUseCredential;
19}
20 } 其他{
21/如果无效,则取消*/
22 处置=NSURLSessionAuthChallengeCancelAuthenticationChallenge
23 }
24 }
25 if (completionHandler) {
26 完成处理程序(处置,凭证);
27}
28}
复制代码
在[self myCustomValidation:challenge]中调用自定义验证流程。如果结果有效,将创建凭据以建立连接。
要自定义验证流程,首先需要取出一个SecTrustRef对象,它是一个执行信任链验证的抽象实体。它包含验证策略(SecPolicyRef)和一系列可信锚证书。我们能做的就是修改它。就这两件事。
1 SecTrustRef trust=challenge.protectionSpace.serverTrust;
获得信任对象后,可以使用以下函数进行验证。
复制代码
1 静态BOOL serverTrustIsVaild(SecTrustRef trust) {
2 BOOL 允许连接=NO;
3
4 //假设验证结果无效
5 SecTrustResultType trustResult=kSecTrustResultInvalid;
6
7 //函数内部从叶节点证书到根证书递归验证
8 OSStatus 状态=SecTrustEvaluate(trust, trustResult);
9
10 if (雕像==noErr) {
11 //kSecTrustResultUnspecified: 系统隐式信任此证书
12 //kSecTrustResultProceed: 用户添加自己的信任锚点并明确告诉系统该证书是值得信任的。
13
14 允许连接=(trustResult==kSecTrustResultProceed
15 || trustResult==kSecTrustResultUnspecified);
16}
17返回allowConnection;
18}
复制代码
什么时候调用这个函数完全取决于你的需要。如果你不想修改验证策略直接调用,那你还在这里! ()︵
域名验证
通过以下代码可以获取当前的验证策略:
1 CFArrayRef 政策参考;
2 SecTrustCopyPolicies(trust,policiesRef);
打印policiesRef后,会发现默认的验证策略包含域名验证,即“服务器证书上的域名是否与请求的域名匹配”。如果您的其中一个证书需要用于连接不同域名的主机,或者您使用IP地址直接连接,那么您可以重置验证策略以忽略域名验证:
复制代码
1 NSMutableArray *策略=[NSMutableArray 数组];
2
3 //BasicX509不验证域名是否相同
4 SecPolicyRef 策略=SecPolicyCreateBasicX509();
5 [策略addObject:(__bridge_transfer id)策略];
6 SecTrustSetPolicies(trust, (__bridge CFArrayRef)policies);
7
8
复制代码
然后调用serverTrustIsVaild()进行验证。
但如果域名没有经过验证,安全性就会大大降低。拿一个浏览器:
想象一下,您想向https://www.real-website.com发送消息,但由于域名劫持,您被带到了https://www.real-website.cn网站。大概有以下两种结果:
如果这个假网站的证书是非CA颁发的假证书,那么浏览器会提醒你这个证书不可信;
该假冒网站还使用CA 颁发的证书。由于我们不验证域名,因此您的浏览器不会给出任何警告。
你可能会问:公钥证书是所有人都可以使用的。钓鱼网站能否将真实的公钥证书返回给我们?
我觉得可以,但是没啥用。没有私钥的网络钓鱼服务器无法获得第三个随机数,无法生成会话密钥,也无法解密我们传递给它的数据。
自签名证书链验证
为了防止App中出现上述的中间人攻击,更好的做法是将公钥证书封装到App中,然后在接收服务器证书链时,可以有效验证服务器是否是值得信赖。这对于验证自签名证书链也是必要的。
假设您的服务器返回:[您的自签名根证书] -- [您的辅助证书] -- [您的客户端证书]。系统不信任这三个证书。
所以验证时需要设置这三者之一作为锚点证书。当然,多份证书也是可以的。
例如,使用[您的辅助证书]作为锚点后,SecTrustEvaluate()函数只需验证[您的客户端证书]确实是由[您的辅助证书]签名的,则验证结果为kSecTrustResultUnspecified,表示[您的客户端]证书] 是可信的。设置锚点证书的方法如下:
复制代码
1 NSMutableArraycertificates=[NSMutableArray 数组];
2
3 NSDatecerData=/您在App Bundle 中用作锚点的证书数据。该证书采用CER 编码。常见的扩展名有:cer、crt./
4
5 SecCertificateRef cerRef=SecCertificateCreateWithData(NULL, (__bridge CFDataRef)cerData);
6
7 [证书addObject:(__bridge_transfer id)cerRef];
8
9 //设置锚点证书。
10 SecTrustSetAnchorCertificates(信任,(__bridge CFArrayRef)证书);
复制代码
如果只调用SecTrustSetAnchorCertificates()函数,那么只有作为参数传入的证书才会被用作锚点证书,甚至系统本身信任的CA证书也无法作为锚点来验证证书链。要恢复CA证书作为系统中锚点的功能,必须再次调用以下函数:
1 //true 表示仅传入的证书用作锚点, false 允许系统CA 证书也用作锚点
2 SecTrustSetAnchorCertificatesOnly(信任,假);
这样调用serverTrustIsVaild()验证证书有效性就会成功。
CA证书链验证
上面说的是对没有经过CA认证的自签名证书的验证,CA的证书链的验证方法是一样的。不同的是,不可信锚点的证书类型不同:前者的锚点是自签名的,需要验证。打包到App中进行验证,后者的锚点可能已经存在于系统中。但我发现了这个陷阱:
如果我们使用一个CA根证书签名的数字证书,并且只用这个CA根证书作为锚点,而不验证域名,那么在握手阶段我们会信任同一个CA根证书签名的伪造证书吗?呢绒?
参考阅读
iOS安全系列一:HTTPS
iOS 安全系列2:HTTPS 高级
正确覆盖TLS 链验证
HTTPS服务器信任评估
如果有什么我理解不正确或者表达不准确的地方,请告诉我。
文/StanOz(简书作者)
原文链接:http://www.jianshu.com/p/31bcddf44b8d
版权归作者所有。转载请联系作者授权并注明“简书作者”。
其他:
公司的接口一般采用两种协议,一种是HTTP,一种是HTTPS。只要HTTP请求,服务器就会响应。如果我们不对请求和响应进行加密,所有信息都将被检测到并被劫持。这是非常不安全的。可以使用我的一套工具来处理客户端加密:文章地址
但任何时候,服务都应该放在HTTPS上,因为它可以避免中间人攻击的问题,而且还带有基于非对称密钥的加密通道!现实情况是,近年来涌现了大量即时移动开发者。这些人往往基础很差,对加密解密毫无了解。使用HTTPS后,你可以省去他们对他们进行各种加密和解密技术的教育,他们的生活会轻松很多。
介绍HTTPS交互原理
简而言之,HTTPS 是HTTP 协议加上SSL 协议的一层加密。 SSL证书符合SSL协议,由受信任的数字证书颁发机构CA(如GlobalSign、wosign)验证服务器身份后颁发。这是要花钱的。颁发的证书一般放在服务器根目录下作为公钥,方便客户端请求返回给客户端。私钥存储在服务器内部中心,用于解密公钥。
HTTPS客户端与服务器交互流程:
1、客户端发送请求,服务器返回公钥给客户端;
2、客户端生成对称加密密钥,用公钥加密,返回给服务器;
3、服务器收到后,使用私钥解锁对称加密密钥并保存;
4、后续所有交互都将使用对称加密数据。
我们来谈谈证书
简单来说,证书有两种,一种是严肃的:
CA颁发的证书
一种是不合时宜的:
自行生成并颁发证书
介绍一下我们需要做什么
如果遇到严重的证书,我们可以直接使用AFNetworking来请求。 AFNetworking帮助我们内部封装了HTTPS请求方法,但是大多数公司接口都不是正经的证书。在这种情况下,我们需要执行以下步骤:
1.将服务器的公钥证书拖入Xcode中
2.修改验证方式
manager.securityPolicy=[AFSecurityPolicy策略WithPinningMode:AFSSLPinningModePublicKey];
原则:
简单来说,您可以修改AFN 设置以允许客户端从服务器接收任何证书。但是这样做有一个问题,就是无法验证该证书是否是你服务器后端的证书,从而允许中间人攻击,即通过重路由的方式。定向路由为在服务器端分析伪造品打开了大门。
AFSecurityPolicy *securityPolicy=[AFSecurityPolicy defaultPolicy];
securityPolicy.allowInvalidCertificates=是;
解决方案:AFNetworking 允许嵌入证书。通过嵌入证书,AFNetworking通过比较服务器端证书、嵌入证书和站点域名来验证连接的服务器是否正确。由于CA证书验证是通过站点域名来验证的,所以如果你的服务器后端有绑定域名的话是最方便的。如果您的服务器端证书是pem格式,请使用以下命令将其转换为cer格式。
openssl x509 -在您的服务器证书.pem -outform der -out server.cer
然后将生成的server.cer文件引入,如果你有自建的ca,加上ca的cer格式证书,放入app的bundle中。 AF网络
AFSecurityPolicy *securityPolicy=[AFSecurityPolicy AFSSLPinningModeCertificate];
或者
AFSecurityPolicy *securityPolicy=[AFSecurityPolicy AFSSLPinningModePublicKey];
在这种情况下,将自动扫描并导入捆绑包中的.cer文件,以便可以通过自签名证书来验证服务器的唯一性。
AFSecurityPolicy具有三种验证模式:
AFSSLPinningMode无
此模式意味着不执行SSL 固定。
就像浏览器一样,它会在系统的受信任权限列表中验证服务器返回的证书。如果证书是由信任机构颁发的,它将通过。如果证书是自己的服务器生成的,就不会通过。
AFSSLPinningMode证书
该模式是指使用证书绑定来验证证书。客户端需要保存服务器证书的副本。这里的验证分为两步。第一步,验证证书的域名有效期等信息。第二步是将服务器返回的证书与客户端进行比较。终端返回的结果是否一致。
好了,文章到此结束,希望可以帮助到大家。
【深入解析iOS平台HTTPS证书链验证机制】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
苹果官方一直很重视用户隐私和安全,这篇文章应该介绍了 iOS 如何确保我们访问网站时数据加密安全
有8位网友表示赞同!
终于可以了解一下手机端HTTPS证书是怎么运作的了,太难懂了...
有12位网友表示赞同!
我最近在学习网络安全,看到这个标题就迫不及待想看
有16位网友表示赞同!
不知道iOS的证书链验证和安卓有什么区别
有7位网友表示赞同!
希望这篇文章能解释清楚HTTPS协议,我一直不太明白它是怎么工作的
有15位网友表示赞同!
如果攻击者绕过证书链认证怎么办?这篇文章会提到吗?
有20位网友表示赞同!
我很好奇 iOS 使用哪些特定的算法来验证证书
有5位网友表示赞同!
最近听说了一些关于网站被盗用、数据泄露的信息,了解安全知识很重要哦!
有9位网友表示赞同!
这个话题看起来很专业,但应该很有趣
有16位网友表示赞同!
看来苹果又升级了新的安全措施
有20位网友表示赞同!
想了解一下如何自己手动查看 iPhone 的证书链验证过程
有10位网友表示赞同!
学习一下这些知识可以保护我们的手机安全
有12位网友表示赞同!
这篇文章能让我更好地理解 iOS 系统的安全性机制吗?
有19位网友表示赞同!
希望看到一些实际案例,来展示 iOS 证书链验证的效果
有15位网友表示赞同!
这个标题看起来很吸引人,一定要去看一看!
有6位网友表示赞同!
也许我还能通过这次学习,编写自己的安全脚本
有16位网友表示赞同!
iOS系统对安全的重视,真是太赞了!
有9位网友表示赞同!
网络安全是一个非常重要的课题,值得我们去深究
有13位网友表示赞同!
看一看这篇文章,就能让自己更加了解手机的运作原理吗?
有14位网友表示赞同!
学习一些关于系统安全的知识永远不会过分!
有5位网友表示赞同!