写给 iOS 开发者看的 HTTPS 指南

 春天来了,到了动物交配强制 ATS(App Transport Security)的季节,广袤的 iOS 大草原上到处都弥漫着一种叫 HTTPS 的荷尔蒙气息。

  苹果在 WWDC 2016 上宣布:2016 年底将要求所有 APP 适配苹果的 App Transport Security,简单地说就是除了特殊情况(浏览器、第三方服务、媒体)外,APP 跟服务端的通信必须使用 HTTPS 协议,否则 iOS 9 和 macOS 10.11 起,操作系统将有能力阻止所有的明文 HTTP 请求。在上面的 session 中,苹果还对具体的细节做出了要求。不过,就在今天,苹果宣布将这个 deadline 无限期推迟。

  本文将着重以大部分 iOS 开发者能理解的方式介绍 APP 启用 HTTPS 支持的过程中跟 APP 相关的部分,剩余的协议细节将一笔带过。

  HTTPS 基础

  定义

  HTTPS 看似跟 HTTP 一样,其实它只是看起来跟 HTTP 一样,实际上是一种新的网络架构。在当前情况下,HTTPS 的英文全称应该是 HTTP over TLS。

  HTTPS 请求 和 HTTP 请求的异同

  普通 HTTP 请求直接基于 TCP,在互联网上明文传播,而且没有任何校验,链路上的每一个节点都可以对数据包进行篡改,使用手机网络访问 HTTP 网站被插入流量球甚至广告等运营商劫持行为就是最常见的例子。而 HTTPS 请求运行在 TLS 层之上,TLS 运行在 TCP 上,TLS 有独特的握手、建立连接、数据验证机制,让运行商劫持无处下手:只要任何一个数据包被篡改,数据校验就会失败,这个请求会客户端直接抛弃,网页不会显示。当我们用 HTTP 协议来解释 TLS 层携带的内容时,这个东西就被称为 HTTPS 啦。

  HTTP 协议简析

  HTTP 协议是一个非常简单而强壮的协议,它规定了以文本方式解析数据后哪一部分该代表什么:头部携带特定信息,正文部分被渲染为网页。所以,任何数据都可以被 HTTP 协议解析,无论他是基于 TCP 还是 TLS 传输,或者只是硬盘上的一个文件。

  请注意,此处的 HTTP 协议和上一小节中的 HTTP 请求是两个概念。

  HTTPS 证书

  证书是什么

  下面两张图分别是我的个人博客的一张旧证书的 cer 和 crt 两种格式,在 Finder 中点击空格预览的结果:

  

  

  下面是 crt 格式的证书内容:

—–BEGIN CERTIFICATE—–

  MIIErzCCA5egAwIBAgIQYrp2Mj1s3GeeVubYEGEguTANBgkqhkiG9w0BAQsFADBV

  ... 省略N个字...

  XKK1E/BNFR7GR8i1NfL15KdIGUmsklT60vooRd7zM9ai8vtmkg9xykwpgUPbTjcd

  mRAb

—–END CERTIFICATE—–

  证书就是使用特殊格式加密的一段字符串,可以被读取并拿出关键信息。iOS 中 NSURLSession 验证的就是 cer 格式的这个证书。

  证书周边知识

  下面是一个 HTTPS 证书典型的购买、部署流程:

  1. 在 *UNIX 环境下使用 openssl 工具生成一对一匹配的 私钥 和 CERTIFICATE REQUEST 文件(以 —–BEGIN CERTIFICATE REQUEST—– 开头)。私钥为绝密,绝对不能泄露,最好在生产服务器直接生成,这样就不需要网络传输,更加安全。

  2. 将 CERTIFICATE REQUEST 文件提交到证书服务机构,服务机构根据证书级别进行 域名认证、公司认证、安全认证 等不同级别的安全验证。

  3. 验证通过后,服务机构将基于我们提交的 CERTIFICATE REQUEST 内容,使用他已有的证书派生出子证书,提供给我们下载。

  4. 我们拿到服务机构颁发的两个 crt 格式的证书(root 证书 及我们的域名证书),再配合本地的私钥,到 Apache、Nginx 等 web server 上部署,部署时会验证“私钥”是否和“域名证书”匹配。

  5. 用户在以 HTTPS 协议访问网站时,浏览器会进行如下几步安全验证:

  • 域名证书中的域名和实际域名是否一致

  • 域名证书和 root 证书是否匹配

  • root 证书是否可信

  需要注意的点

  1. 在某些低安全级别证书申请中(如仅验证域名所有权的证书),私钥可以让签发服务器代为生成,但这样做有一定的安全风险。

  2. root 证书也可以在我们本机生成,如 12306 的自签名证书,但这样不会被普通浏览器信任。

  3. 私钥为绝密,因为证书全部都是公开的,任何人都可以提取,如果私钥被别人获取,被部署到别人的服务器中,那所有人就会认为那台服务器是完全合法的。这已经不是中间人攻击了,这时候他就是你。

  NSURLSession 对证书的验证

  证书验证方法

  在 URLSessionDelegate 中有一个方法 func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 专门用来处理 HTTPS 证书的处理。具体操作可以参考 Pitaya 中的代码。

  我简单复述一下处理流程:

  1. 发现是 HTTPS 请求,取出证书

  2. 进入证书处理流程:

    1. 本地证书分两种情况:① 本地存储着证书服务机构颁发的 crt 文件转换而来的 cer 文件,使用 NSData 进行内容对比 ② 本地存储着自签名的 cer 格式的证书,使用 NSData 进行内容对比

    2. 匹配成功,手动让请求继续,这一步可以让自签名证书绕过 iOS 系统的证书合法性验证

    3. 匹配失败,进入错误处理流程

    4. 如果自签名证书不做手动处理,那么在这个方法结束后链接就会被系统关闭,因为 root 证书不合法。

  所以,在 APP 提交的时候,苹果会检查是否将 ATS 配置为了“全部无脑通过”,这种操作是被禁止的。当然,苹果也可以在系统层面一刀切,但是那样得挂多少个 APP 啊,苹果不会那么做。所以会被影响的应该只是新提交的 ipa。

  SSL 钢钉原理

  如果有人通过一些手段通过了域名所有权认证(非常容易,域名邮箱、DNS指向甚至在根目录放一个文件都可以验证通过),拿到了一个合法的对应你的域名的 HTTPS 证书,这时候他在广场开放了一个没有密码的 wifi,命名为 CMCC,这样,几乎所有的开着 wifi 的手机都会自动连接,这时候他只需要做一个简单的 DNS 劫持,就可以把所有应该向你网站发送的需求劫持到他那里。

  但是:如果你做了 SSL 钢钉验证,那么他的证书就不会被验证通过。他也没法用你的证书启动服务,因为私钥和证书的验证是 SSL 协议强制做的,他没有你的私钥,他的 web server 就没法启动。所以,私钥千万不能泄露。

  关于自签名证书

  自签名证书不会被浏览器信任,因为每次有新的 HTTPS 证书到达某个操作系统时,系统会去访问 root 证书的服务器以确定域名证书的身份,这些合法的 root 证书服务商就是固定的那几家,显然自签名证书不会被信任,所以我们在 12306 抢票的时候需要先下载他的自签名证书的 root 证书并手动信任,不然就打不开页面。

  我们可以看到,自签名证书的验证在代码层面,在审核的时候是完全不可感知的,所以就没有什么“苹果不接受自签名证书”之类的问题了。而且,自签名证书被广泛的用于各种系统内部的连接加密,不是苹果可以一刀切的:如果粗暴的在操作系统层面阻止了自签名证书,导致企业客户的系统突然挂掉,后果不可想象。

  关于证书更换

  证书都有有效期,在过期之前需要申请新证书,这时候 SSL 钢钉该怎么处理呢?动态下发当然是不行的,为什么要验证证书?就是因为网络不可信任。Pitaya 前两天加入了这个逻辑:在新证书和旧证书交接的一段时间内,上线新版本,同时包含新旧证书,这样可以保证更新过的用户可以对证书更换无感。

  另外,设置 SSL 钢钉不适合面向普通用户的 APP,因为总是有人万年不更新,这更适合企业内部 APP,可以通过行政手段及自驱力(业绩啊,提成啊)推动更新。

  关于所谓的双向验证

  感觉这里是大家误解最大的地方:大部分人所谓的“双向验证”就是自签名证书的验证并手动继续而已。

  HTTPS 是支持双向认证的,不过那指的是客户端(浏览器或 APP)也像服务端一样,在发送请求给服务端的时候带上证书,再由服务端使用对应的私钥进行验证。一般 APP 不需要这么做。

  苹果的要求

  后端

  

  前两条拿给后端看就行,第三条用 Nginx 也很容易实现。最后一条 Exception 就是苹果马上就不支持的。

  iOS 端

  

  使用这些 API 可以单独绕过。

  

  流媒体文件可以添加例外,WKWebView 可以直接设置为绕过。

  总结

  购买的证书:什么都不用管,改一下服务器地址就行,代码完全不用改。

  自签名证书:找后端哥们儿要一个 crt,自己提取也行,转换成 cer ,放到相应的方法里,手动让处理流程继续即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值