写给 iOS 开发者看的 HTTPS 指南

https://autolayout.club/2016/12/22/写给-iOS-开发者看的-HTTPS-指南/


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 格式的证书内容:


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

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

在 *UNIX 环境下使用 openssl 工具生成一对一匹配的 私钥 和 CERTIFICATE REQUEST 文件(以 —–BEGIN CERTIFICATE REQUEST—– 开头)。私钥为绝密,绝对不能泄露,最好在生产服务器直接生成,这样就不需要网络传输,更加安全。
将 CERTIFICATE REQUEST 文件提交到证书服务机构,服务机构根据证书级别进行 域名认证、公司认证、安全认证 等不同级别的安全验证。
验证通过后,服务机构将基于我们提交的 CERTIFICATE REQUEST 内容,使用他已有的证书派生出子证书,提供给我们下载。
我们拿到服务机构颁发的两个 crt 格式的证书(root 证书 及我们的域名证书),再配合本地的私钥,到 Apache、Nginx 等 web server 上部署,部署时会验证“私钥”是否和“域名证书”匹配。

用户在以 HTTPS 协议访问网站时,浏览器会进行如下几步安全验证:
1、域名证书中的域名和实际域名是否一致
2、域名证书和 root 证书是否匹配
3、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、进入证书处理流程:
2-1、本地证书分两种情况:① 本地存储着证书服务机构颁发的 crt 文件转换而来的 cer 文件,使用 NSData 进行内容对比 ② 本地存储着自签名的 cer 格式的证书,使用 NSData 进行内容对比
2-2、匹配成功,手动让请求继续,这一步可以让自签名证书绕过 iOS 系统的证书合法性验证
2-3、匹配失败,进入错误处理流程
2-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
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值