本文来自于腾讯Bugly公众号(weixinBugly),原文地址:https://mp.weixin.qq.com/s/-fLLTtip509K6pNOTkflPQ
我是带着一系列的问题,找到了这篇文章,很好地解答我的疑惑!
1.怎么抓HTTPS的包?
2.中间人攻击是什么?解决方案?
3.https通讯的话,代码怎么实现CA证书校验?
4.CA证书校验都有哪些类型可以检验 ?

本文分为三部分:
* 分析下对服务器身份验证的完整握手过程
* 证书链的验证
* 探索iOS中原生库NSURLConnection或NSURLSession如何支持实现https。

通常我们会访问HTTPS://xxx的网站,当你在浏览器地址栏输入支持HTTPS协议的URL地址后,服务器返回的数据会显示在页面上。对于不了解HTTPS协议工作原理的小伙伴可能觉得这个过程很简单:发送请求-服务器响应请求-结果返回并显示。但对于HTTPS而言,在整个发送请求返回数据过程中还涉及到通讯双方证书验证、数据加密、数据完整性校验等。

引入HTTPS是为了解决HTTP所带来的三个问题:
* HTTP是明文传输,数据容易被窃取,因此要加密数据以防止数据中途窃取
* 认证服务器身份,确保数据发送到正确的服务器
* 维护数据的完整性,防止数据在传输中被改变,如中间人攻击

下面以登录qq邮箱为例,通过Wireshark抓包可以看到如下图:

从图中可以看到:在浏览器与服务器进行传输通信数据之前,还经历了Client Hello-Server Hello-Client Key Exchange-Change Cipher Spec等过程。

上述单向验证的完整握手过程,总结如下:

第一阶段:ClientHello
客户端发起请求,以明文传输请求信息,包含版本信息,加密套件候选列表,压缩算法候选列表,随机数random_C,扩展字段等信息。

第二阶段:ServerHello-ServerHelloDone
如上图可以看出这个阶段包含4个过程( 有的服务器是单条发送,有的是合并一起发送)。服务端返回协商的信息结果,包括选择使用的协议版本,选择的加密套件,选择的压缩算法、随机数random_S等,其中随机数用于后续的密钥协商。服务器也会配置并返回对应的证书链Certificate,用于身份验证与密钥交换。然后会发送ServerHelloDone信息用于通知服务器信息发送结束。

第三阶段:证书校验
在上图中的5-6之间,客户端这边还需要对服务器返回的证书进行校验。只有证书验证通过后,才能进行后续的通信。(具体分析可参看后续的证书验证过程)

第四阶段:ClientKeyExchange-Finished
服务器返回的证书验证合法后, 客户端计算产生随机数字Pre-master,并用server证书中公钥加密,发送给服务器。同时客户端会根据已有的三个随机数根据相应的生成协商密钥。客户端会通知服务器后续的通信都采用协商的通信密钥和加密算法进行加密通信。然后客户端发送Finished消息用于通知客户端信息发送结束。

第五阶段:服务器端生成协商密钥
服务器也会根据已有的三个随机数使用相应的算法生成协商密钥,会通知客户端后续的通信都采用协商的通信密钥和加密算法进行加密通信。然后发送Finished消息用于通知服务器信息发送结束。

第六阶段:握手结束
在握手阶段结束后,客户端和服务器数据传输开始使用协商密钥进行加密通信。

总结
简单来说,HTTPS请求整个过程主要分为两部分。一是握手过程:用于客户端和服务器验证双方身份,协商后续数据传输时使用到的密钥等。二是数据传输过程:身份验证通过并协商好密钥后,通信双方使用协商好的密钥加密数据并进行通信。在握手过程协商密钥时,使用的是非对称密钥交换算法, 密钥交换算法本身非常复杂,密钥交换过程涉及到随机数生成,模指数运算,空白补齐,加密,签名等操作。在数据传输过程中,客户端和服务器端使用协商好的密钥进行对称加密解密。

证书

PKI (Public Key Infrastructure),公开密钥基础设施。它是一个标准,在这个标准之下发展出的为了实现安全基础服务目的的技术统称为PKI。 权威的第三方机构CA(认证中心)是PKI的核心, CA负责核实公钥的拥有者的信息,并颁发认证”证书”,同时能够为使用者提供证书验证服务。 x.509是PKI中最重要的标准,它定义了公钥证书的基本结构。

证书申请过程

证书申请者向颁发证书的可信第三方CA提交申请证书相关信息,包括:申请者域名、申请者生成的公钥(私钥自己保存)及证书请求文件.cer等

CA通过线上、线下等多种手段验证证书申请者提供的信息合法和真实性。

当证书申请者提供的信息审核通过后,CA向证书申请者颁发证书,证书内容包括明文信息和签名信息。其中明文信息包括证书颁发机构、证书有效期、域名、申请者相关信息及申请者公钥等,签名信息是使用CA私钥进行加密的明文信息。当证书申请者获取到证书后,可以通过安装的CA证书中的公钥对签名信息进行解密并与明文信息进行对比来验证签名的完整性。

证书验证过程:
验证证书本身的合法性(验证签名完整性,验证证书有效期等)
验证证书颁发者的合法性(查找颁发者的证书并检查其合法性,这个过程是递归的)
证书验证的递归过程最终会成功终止,而成功终止的条件是:证书验证过程中遇到了锚点证书,锚点证书通常指:嵌入到操作系统中的根证书(权威证书颁发机构颁发的自签名证书)。

证书验证失败的原因
1.无法找到证书的颁发者
2.证书过期
3.验证过程中遇到了自签名证书,但该证书不是锚点证书。
4.无法找到锚点证书(即在证书链的顶端没有找到合法的根证书)
5.访问的server的dns地址和证书中的地址不同

iOS实现支持HTTPS

在OC中当使用NSURLConnection或NSURLSession建立URL并向服务器发送https请求获取资源时,服务器会使用HTTP状态码401进行响应(即访问拒绝)。此时NSURLConnection或NSURLSession会接收到服务器需要授权的响应,当客户端授权通过后,才能继续从服务器获取数据。如下图所示:

非自签名证书验证实现

在接收到服务器返回的状态码为401的响应后,对于NSURLSession而言,需要代理对象实现URLSession:task:didReceiveChallenge:completionHandler:方法。对于NSURLConnection而言,需要代理对象实现connection:willSendRequestForAuthenticationChallenge: 方法(OS X v10.7和iOS5及以上),对于早期的版本代理对象需要实现代理对象要实现connection:canAuthenticateAgainstProtectionSpace:和connection:didReceiveAuthenticationChallenge:方法。代码如下(参考文档):

当客户端发送https请求后,服务器会返回需要授权的相关信息,然后connection:willSendRequestForAuthenticationChallenge:方法被调用。客户端根据返回的challenge信息,首先获取需要验证的信任对象trust,然后调用SecTrustEvaluate方法是用系统默认的验证方式对信任对象进行验证,当验证通过时,使用该信任对象trust生成证书凭证,然后self.connection使用该凭证继续连接。如下详解:

NSURLAuthenticationChallenge包含如下信息:
error :最后一次授权失败的错误信息
failureResponse :最后一次授权失败的错误信息
previousFailureCount :授权失败的次数
proposedCredential :建议使用的证书
protectionSpace :NSURLProtectionSpace对象,代表了服务器上的一块需要授权信息的区域。包括了服务器地址、端口等信息。在此指的是challenge.protectionSpace。其中Auth-scheme指protectionSpace所支持的验证方法,NSURLAuthenticationMethodServerTrust指对protectionSpace执行证书验证。

表示需要验证的信任对象(Trust Object),在此指的是challenge.protectionSpace.serverTrust。包含待验证的证书和支持的验证方法等。

SecTrustRef
表示需要验证的信任对象(Trust Object),在此指的是challenge.protectionSpace.serverTrust。包含待验证的证书和支持的验证方法等。

SecTrustResultType
表示验证结果。其中 kSecTrustResultProceed表示serverTrust验证成功,且该验证得到了用户认可(例如在弹出的是否信任的alert框中选择always trust)。 kSecTrustResultUnspecified表示 serverTrust验证成功,此证书也被暗中信任了,但是用户并没有显示地决定信任该证书。 两者取其一就可以认为对serverTrust验证成功。

SecTrustEvaluate
函数内部递归地从叶节点证书到根证书验证。使用系统默认的验证方式验证Trust Object,根据上述证书链的验证可知,系统会根据Trust Object的验证策略,一级一级往上,验证证书链上每一级证书有效性。

NSURLCredential
表示身份验证证书。URL Lodaing支持3种类型证书:password-based user credentials, certificate-based user credentials, 和certificate-based server credentials(需要验证服务器身份时使用)。因此NSURLCredential可以表示由用户名/密码组合、客户端证书及服务器信任创建的认证信息,适合大部分的认证请求。对于NSURLCredential也存在三种持久化机制:

NSURLCredentialPersistenceNone :要求 URL 载入系统 “在用完相应的认证信息后立刻丢弃”。
NSURLCredentialPersistenceForSession :要求 URL 载入系统 “在应用终止时,丢弃相应的 credential ”。
NSURLCredentialPersistencePermanent :要求 URL 载入系统 “将相应的认证信息存入钥匙串(keychain),以便其他应用也能使用。
对于已经验证通过的信任对象,客户端也可以不提供证书凭证。

对于NSURLSession,传递如下之一的值给completion handler回调:
NSURLSessionAuthChallengePerformDefaultHandling处理请求,就好像代理没有提供一个代理方法来处理认证请求
NSURLSessionAuthChallengeRejectProtectionSpace拒接认证请求。基于服务器响应的认证类型,URL加载类可能会多次调用代理方法。
对于 NSURLConnection 和 NSURLDownload,在[challenge sender] 上调用continueWithoutCredentialsForAuthenticationChallenge:方法。不提供证书的话,可能会导致连接失败,调用connectionDidFailWithError:方法 ,或者会返回一个不需要验证身份的替代的URL。 如下代码:

对于非自签名的证书,即使服务器返回的证书是信任的CA颁发的,而为了确定返回的证书正是客户端需要的证书,这需要本地导入证书,并将证书设置成需要参与验证的锚点证书,再调用SecTrustEvaluate通过本地导入的证书来验证服务器证书是否是可信的。如果服务器证书是这个锚点证书对应CA或者子CA颁发的,或服务器证书本身就是这个锚点证书,则证书信任通过。如下代码(参考文档):

自签名证书验证实现
对于自签名证书,这样Trust Object中的服务器证书是不可信任的CA颁发的,直接使用SecTrustEvaluate验证是不会成功的。可以采取下述简单代码绕过HTTPS的验证:

上述代码一般用于当服务器使用自签名证书时,为了方便测试,客户端可以通过该方法信任所有自签名证书。

综上对非自建和自建证书验证过程的分析,可以总结如下:
1.获取需要验证的信任对象(Trust Object)。对于NSURLConnection来说,
是从delegate方法-connection: willSendRequestForAuthenticationChallenge:回调回来的参数challenge中获取(challenge.protectionSpace.serverTrust) 。
2.使用系统默认验证方式验证Trust Object。SecTrustEvaluate会根据Trust Object的验证策略,一级一级往上,验证证书链上每一级数字签名的有效性,从而评估证书的有效性。
3.如第二步验证通过了,一般的安全要求下,就可以直接验证通过,进入到下一步:使用Trust Object生成一份凭证([NSURLCredential credentialForTrust:serverTrust]),传入challenge的sender中([challenge.sender useCredential:cred forAuthenticationChallenge:challenge])处理,建立连接。
4.假如有更强的安全要求,可以继续对Trust Object进行更严格的验证。常用的方式是在本地导入证书,验证Trust Object与导入的证书是否匹配。
5.假如验证失败,取消此次Challenge-Response Authentication验证流程,拒绝连接请求。
6.假如是自建证书的,则不使用第二步系统默认的验证方式,因为自建证书的根CA的数字签名未在操作系统的信任列表中。

iOS中HTTPS证书验证浅析相关推荐

  1. https证书验证的基本方法

    https证书是一种数字证书,这种证书的主要作用是保护网站的信息安全,此时就能够提高网站的安全性.不过,网站配置了https证书之后一定要进行https证书验证,这种情况下的安全性是很高的.但是,ht ...

  2. http三次握手_【吊打面试,击中要害】http三次握手四次挥手,https证书验证阶段和数据传输阶段...

    阅读文本大概需要3分钟. PPT: Jenkins与项目构建部署工具集成 0x01:tcp三次握手,四次挥手 三次握手(Three-way Handshake),是指在建立一个TCP连接时候,需要客户 ...

  3. idea验证失败_SVN提示https证书验证失败解决办法

    技术分享之 <SVN提示https证书验证失败解决办法>--我要编程技术手册系列 svn提交代码时报错,证书认证失败 Commit failed with error 0 files co ...

  4. android 服务器证书校验,Android HTTPS证书验证的简单方式

    1. 背景与需求 近期在做IP切换的HTTPS访问时,遇到了一些问题:客户端如何进行HTTPS的证书验证. 其实对于一般的项目基本都是做的单向验证,即在客户端证书或者HOST的验证:对于金融.银行相关 ...

  5. java证书验证失败_解决https证书验证不通过的问题

    1.报错信息 java.security.cert.CertificateException: No name matching api.weibo.com found; nested excepti ...

  6. java.security.cert.CertificateException: No name matching https证书验证不通过

    1.报错信息 1 java.security.cert.CertificateException: No name matching api.weibo.com found; nested excep ...

  7. iOS中https的证书验证

    文/大风歌飞鼎折覆餗(简书作者) 原文链接:http://www.jianshu.com/p/f10f6df67d66 著作权归作者所有,转载请联系作者获得授权,并标注"简书作者" ...

  8. https 证书验证等原理

    签名是指利用上一层证书的私钥,加密一些元信息(证书所有者的信息,包括基本信息,公钥,证书生效域名等).这样,当收到签名证书时,只需要根据CA提供的公钥对签名解密,验证元信息是否一致,就可以判断当前证书 ...

  9. 解决SVN提示https证书验证失败问题svn: E230001: Server SSL certificate verification failed: certificate issued

    svn: E230001: Server SSL certificate verification failed: certificate issued 今天在使用svn时候发现出现这个问题,这个是因 ...

  10. iOS 中对 HTTPS 证书链的验证

    这篇文章是我一边学习证书验证一边记录的内容, 稍微整理了下,共扯了三部分内容: HTTPS 简要原理: 数字证书的内容.生成及验证: iOS 上对证书链的验证. HTTPS 概要 HTTPS 是运行在 ...

最新文章

  1. excel打开csv错误换行_「乱吐槽·乱学习」excel高手捷径:一招鲜,吃遍天③
  2. 远程过程调用RPC RMI(Remote Method Invocation)和Web Service
  3. Java高级语法笔记-向上层抛出异常
  4. ArrayList 动态数组 0119
  5. (转)互联网——降级论
  6. python网站用什么数据库_使用python读取mysql数据库并进行数据的操作
  7. 中国喷漆室保护膜市场趋势报告、技术动态创新及市场预测
  8. nodemcu引脚_一、ESP32开发板NodeMCU-32S简介
  9. phoenix timestamp字段查询
  10. ViT (Vision Transformer) ----LSTM网络
  11. ubuntu1604 安装samba
  12. 狂打气球html5游戏_4399h5游戏_企业团建活动小游戏:合力吹气球
  13. 另存为fdf或xps加载项_2007 Microsoft Office加载项:Microsoft另存为PDF或XPS
  14. 李占通他道出了我的心声
  15. mediawiki java api_MediaWiki API 帮助
  16. 1010 - 线性dp - 除虫药水
  17. java抽象类有什么用_java中抽象类的作用是什么?抽象类作用的例子
  18. 破解Windows7开机密码
  19. man posix_spawn
  20. 什么耳机适合跑步、分享五款公认最好的跑步耳机

热门文章

  1. 微信头像 尺寸 php,怎么把照片缩小做微信头像
  2. 美图秀秀证件照发现不能用了了,俩个 一寸照片,俩寸证件照 证件照在线的网址记录一下,
  3. 小菜鸟的Python笔记002:如何识别Word文档中的复选框
  4. 什么是中药药浴?中药药浴的操作方法和注意事项
  5. 2021-08-28-n皇后问题
  6. 交换机端口vlan tag/untag处理情况
  7. android上查看浏览器内核版本号,各种浏览器的userAgent及如何使用JS来检测游览器类型,或android是什么版本号...
  8. PHP配置优化《MordenPHP》
  9. 自我觉察6-我的价值感?
  10. UDP的单播广播和组播