IOS应用安全-HTTP/HTTPS网络安全(一)

导读:

本文主要讲在HTTP和HTTPS实际开发中有用和有意思的地方,希望读者能够有所启发。

主要包括:HTTP和HTTPS的简单介绍。介绍HTTPS加密逻辑。介绍SSL证书和SSL证书校验的规则。

本文简化了相关的技术细节,主要关注于前端开发需要关注的点和可以借鉴的地方,希望能对开发能有所帮助。开发更关心的技术代码实现细节,会单独文章中说明。

HTTP简介

具体细节可以参考后面的参考文献,只写我觉得有意思和实际中可以参考的地方。

  1. HTTP协议构建于TCP之上。意味着http是可靠的数据传输。所以不用担心丢包和乱序的问题。

  2. HTTP协议是基于请求和响应的协议。与之对比MQTT协议是基于订阅的协议。

    比如我想要一个资源的种子,如果知道哪个老司机有,我直接问他,他有就给我,没有也告诉我没有。这种模式就是请求和响应,好处是一对一,可以准确完整的按照自己的需求拿到需要的数据,但是坏处是消息会滞后,我想知道老司机后面是不是有资源了,我就只能一遍遍重复的问,直到拿到想要的结果为止(循环延迟请求,之前专门写个looperRequest就是为了解决这种问题)。

    另外一种方案,我发布消息到一个论坛,然后留下邮箱,求好人一生平安。然后很多好人有资源就发给我,这样也能拿到数据。这种模式就是订阅模式,好处是可以一对多,可以快速实时拿到数据。但是坏处是:需要长链接,且推送消息时不清楚客户端的状态,推送的东西不一定需要,比如这个种子可能我已经有了,再发给我就浪费大家的流量了。

    总结下。利用请求应答的模式,可以快速的和服务端同步数据,保证当前请求数据的有效性,有时候我们也叫拉(pull)数据。订阅模块可以快速的更新需要保证实时性的数据,比如聊天数据,交易结果,账户异常,有时候我们也叫推送(push)数据。

    这两种方案是和服务端常用的两种交互方案,有些交互可以考虑两者结合的方式解决。比如之前项目中解决聊天数据的实时有效性,就采用后端推送当前有新消息或其他状态信息,前端收到状态信息后,主动拉取消息到本地,既能保证能够快速更新消息或状态,又能通过本地的状态,按照需求拉取需要的消息。

    推/拉这种设计思路也可以用于应用间的数据同步,应用于模块间数据通信来进行模块解耦等。现在的项目工程模块化设计方案也借鉴了这两种思想。

  3. URL。URL定义了一个资源的地址。大部分格式如下

    protocol :// hostname[:port] / abs_path / [;parameters][?query]#fragment

    详细说明参考

    其中query用“&”符号隔开,每个参数的名和值用“=”符号隔开。例如:http://www.joes.com/inventory-check.cgi?item=12731&color=blue。唯一需要注意的是,URL里面不容许有非ASCII字符(常见的就是汉字),也不容许有保留字符比如:!*'\"();:@&=+$,/?%#[]%,所以通常拼接请求时(GET),需要对传进来的参数做一次URLEncode操作。

    可以参考这个做私有协议跳转,比如push消息协议,模块跳转协议,外部跳转协议等。

  1. http请求由三部分组成,分别是:请求行、消息报头、请求正文.详细的建议使用charles抓一个请求看下就知道了。

    注:来源于http://www.cnblogs.com/ranyonsue/p/5984001.html.

    重要的几个请求报头字段:

    • Accept: 指定客户端接受的消息类型(通常没人使用,因为客户端大量使用json做数据解析)
    • Host:请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的
    • User-Agent:用于附加操作系统名称和浏览器版本,通常给H5使用的,UA很容易被修改,项目中有遇到修改UA导致H5页面识别不出来当前操作系统和版本的问题,遇到这种可以查下UA被谁篡改了。
    • Referer:用于标示请求来源,一般用于防盗链,这个实际中也遇到过。
  2. http的响应一般由三个部分组成,分别是:状态行,消息报头,响应正文。


    注:来源于http://www.cnblogs.com/ranyonsue/p/5984001.html.

    重要的几个消息报头

    • Content-Type 正文媒体类型和编码格式,比如:Content-Type:text/html;charset=ISO-8859-1.Content-Type这个字段被AFNetworking框架用于决定用什么解析器,注意后端不要配置错了。charset被用于AFNetworking字符解码,也应该前后端配置正确。这个配置不正确是经常联调不过的原因。 具体实现参考AFURLResonseSerialization.m
    • Content-Length 用于表示正文长度,下载长资源时,需要使用这个字段来计算进度,也可以用这个字段推算下载流量。
    • Content-Encoding 通常用于记录压缩方法,比如:gzip
  3. GET和POST的方法。HTTP有定义了几种常用的方法,不过通常前端只和这两个打交道。这两个区别:

    • 通常认为get是获取消息,不改变数据,post是用来改变数据,不过实际中,并不是那么明确。
    • get参数是附在URL链接上的,参数拼接前需要做URLEncode,post是附在请求正文里的,格式为key=value,使用&分割,所以对传入数据也要做URLEncode,拼接后和头部用回车换行隔开。
    • get的URL长度有一定限制,不过也取决于系统支持,具体长度需要实际调研,ie的限制为2083字节,post理论上不存在长度限制。
    • 安全性,post相对安全,get相对不安全。不过post属于防君子不防小人的那种,实际没有什么安全可言。
      所以综合来说,如果没有技术洁癖,建议都用post处理。
  4. 上传图片等二进制资源。上传资源一般是post协议,但是通常post是用于传送文本的,如何传图片等资源呢?就需要multipart协议了。

    mutipart和普通的post有两点不同:请求头,请求报文。其中关键字是boundary这个属性。

    • 请求头: 必须包含content-Type,且值为:multipart/form-data;boundary=${bond},其中${bound}为具体分割符,在AFNetworking中,如果不指定是Boundary+${random}
    • 请求体:内容不再是用name=value的形式,而是使用上面的boundary进行分割的一段一段的结构体。具体示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    POST /btoa/work/common/uploadImage HTTP/1.1
    Host: www.example.com
    Content-Type: multipart/form-data; boundary=Boundary+49F77F66A65EEA58
    Cookie: BIGipServerPOOL_PACLOUD_STGR2016080900646=1274288556.52384.0000; FF_SESSION2_ID=Sf503bee3691b4a31a53c6e3c5ae1c1f00912e8
    Connection: keep-alive
    Accept: */*
    User-Agent: FFProject/2.0.0 (iPhone; iOS 10.3.1; Scale/3.00)
    Accept-Language: zh-Hans-CN;q=1, th-TH;q=0.9
    Content-Length: 418864
    Accept-Encoding: gzip, deflate
    --Boundary+49F77F66A65EEA58
    Content-Disposition: form-data; name="ffAppID"
    10004
    --Boundary+49F77F66A65EEA58
    Content-Disposition: form-data; name="imageSeq"
    1
    --Boundary+49F77F66A65EEA58
    Content-Disposition: form-data; name="imageType"
    5
    --Boundary+49F77F66A65EEA58
    Content-Disposition: form-data; name="image"; filename="xxxx.jpg"
    Content-Type: image/jpeg
    ***image hex data***
    --Boundary+49F77F66A65EEA58--

    看到上面的例子可以知道,有几个参数是必须的,name、filename、Content-Type、具体资源数据 ,对应的AF接口:

    1
    2
    3
    4
    - (void)appendPartWithFileData:(NSData *)data
    name:(NSString *)name
    fileName:(NSString *)fileName
    mimeType:(NSString *)mimeType;

HTTPS简介

苹果ATS政策出来之前,后端极少使用HTTPS协议,而是使用HTTP协议+自定义的安全数据加密策略来保证安全性。这是因为虽然HTTPS更安全,但是也更加耗费性能。如今苹果强推HTTPS(有说法是苹果可能会全面禁止HTTP的使用),使得HTTPS大范围使用,并且使用HTTPS作为安全扫描项,被安全机构接纳。但是如果不正确的使用HTTPS,还是会带来安全风险。

SSL/TLS简介

HTTPS的关键字就是SSL(TLS)。和HTTP唯一的不同就是加入了SSL(TLS)协议,这一层在TCP之上,负责保证安全连接和数据传输安全。

注:来自 深入解析HTTPS

SSL实际上是一套加密通信机制。SSL和TLS两者的协议基本一致,区别简单可以理解是TLS是SSL的升级版本。但是使用SSL所有协议版本都不再安全。请勿使用SSL协议 具体可以参考SSL与TLS的区别以及介绍

ios加入了ATS限制,强制原来HTTP必须使用HTTPS传输,也强制要求服务器必须使用TLS v1.2版本以上。所以简化为:

要使用支持TLS1.2及以上协议的HTTPS传输数据

PS:后面如无特殊说明,不再区分TLS和SSL,统一称为SSL

HTTPS原理

建议看下浅析HTTPS中间人攻击与证书校验阮一峰:图解SSL/TLS协议SSL、TLS协议格式入门学习 - .Little Hann

下面是协议流程图:

注:来自http://blog.csdn.net/muzhengjun/article/details/53379593

简单描述:

  1. TCP握手
  2. SSL握手,握手成功就开始传输,失败就断开链接
  3. 数据传输

下面也是只讲一些有意思的点和注意的地方。

HTTPS加密流程

整个加密的流程,体现了一个非常安全的信息加密的方案。 简化的流程如下:

  1. 客户发送一个随机数给服务端:random-c(明文)
  2. 服务端发送自己SSL证书给客户端。发送服务端随机数:random-s(明文)
  3. 客户端验证SSL证书有效性,如果判定有效,生成一个随机数random-p,然后使用证书中的公钥进行非对称加密,发送给服务端。 (这一步是整个安全环节最重要也是最薄弱的环节)
  4. 服务端拿到加密后的秘钥,通过私钥解密,得到random-p ,将random-c、random-s、random-p三个随机数做因子,两端都按照一定算法生成会话对称秘钥secret_key。
  5. 客户端计算之前的握手消息(除了Change Cipher Spec外)的Hash值,利用secret_key做对称加密后发给服务端。
  6. 服务端拿到后,利用secret_key解密,然后利用同样的算法计算之前的握手消息的Hash值,如果能解密成功,且验证Hash值正确则说明客户端的加密算法和秘钥没问题。
  7. 服务端再计算之前的握手消息的Hash值,利用secret_key做对称加密后发给客户端,客户端如果能够解密出来,且与自己计算的Hash值相同,则最后链接正式建立成功。

注明:上面是以RSA为基础的秘钥加密流程,即需要客户端将随机数加密传输给后端。还有一种基于秘钥交换的形式,双方的对称秘钥是通过交换的参数本地的,不会通过信道传输,会更安全些。具体参考TLS/SSL 高级进阶

先简单说明几个概念,详细的会专门抽出来分享:

  1. 对称加密:双方使用的秘钥是相同的,使用同一个秘钥进行加解密。
  2. 非对称加密:加密使用公钥加密,解密使用私钥加密。或者私钥加密,使用公钥解密。但是公钥和私钥是不同的。公钥是公开的,可以被第三方拿到而不会引起任何安全问题,因为通过公钥是无法得到私钥的,因而没办法解密使用公钥加密的数据。
  3. 散列(hash):散列变换是指把文件内容通过某种公开的算法,变成固定长度的值(散列值),这个过程可以使用密钥也可以不使用。这种散列变换是不可逆的,也就是说不能从散列值变成原文。好的散列算法是一对一的,不同的原文生成的一定是不同的散列。

这其中使用的加密策略:

  1. 传输数据应该加密,整个加密过程使用了两种加密方案,一种对称加密,一种非对称加密。
  2. 传输数据使用了对称加密,而秘钥生成中使用了非对称加密。
  3. 使用了散列算法(hash)来做数据验证。

回答这里面常见的几个问题:

  1. 为什么又要用非对称加密,又要用对称加密,只使用一个不可以么?

    不能只是用对称加密,因为对称加密,两个使用的秘钥是一致的,有一端的秘钥泄露了,两端的通信就不再安全了,尤其是客户端的对称秘钥非常容易泄露,拿到秘钥后,整个系统就不安全了。

    也不只用非对称加密,主要是因为性能,非对称加密相对于对称加密,计算时间要长非常多,对于性能要求很高的场景,会明显降低性能。RSA算法和AES算法性能测试

    所以设计者结合了两种方案。两端通过非对称加密协商秘钥,攻击者因为拿不到私钥,是无法解开通信秘钥的。一旦协商成功,通过对称加密又解决了性能问题。

  2. 为什么使用三个随机数

    还是为了进一步加强安全,客户端或者服务端生成的随机数可能是伪随机的,有可能被攻击者猜出,但是如果三个伪随机的数一起使用就大大加强了随机性,这样攻击者就很难破解了。

  3. 为什么最后要做hash验证

    为了保证两端通信中的数据不会做篡改,由于HASH算法,可以保证唯一性,所以如果中间消息被人篡改,就可以断开链接。

如果对原理不感兴趣,那建议记住下面推荐的加密方案,完全可以解决大部分的加密需求:

  1. 使用随机数做对称加密秘钥,将对称加密秘钥使用公钥进行非对称加密传给后端。这样因为秘钥随机,所以即使客户端被破解,也拿不到任何对称秘钥。而公钥建议老客户过3456让她进行动态获取,避免私钥泄露带来的问题。
  2. 使用非对称加密秘钥,可以保证网络数据即使劫持,因为没有私钥,也解不出来对应的加密秘钥,所以加密的隐私数据也是安全的
  3. 两者结合,可以保证一定的性能要求。
  4. 对数据进行加签(加盐+hash算法),保证中间的数据不会篡改。

ps:用户的密码,因为保密性要求更高。建议的算法是做HMAC哈希做脱敏,然后使用非对称加密给后端。

常用的网络传输攻击手段

先思考下,刚才的通信链路有三个参与者:

  1. 客户端
  2. 传输信道
  3. 服务端

如果新加入一个攻击者,他想要窃取用户的隐私数据,他该怎么做?常见的做法:

  1. 攻击客户端。对于IOS系统来说,非越狱手机,由于权限问题,几乎无法攻击(之前XcodeGhost真的是很nb的攻击思路)。对于越狱手机,通过HOOK API,然后重新打包应用,诱导用户下载。或者劫持系统的输入框等常用控件可以达到攻击目的。相关的以后整理输出。但是从移动APP来说,直接攻击APP带来的危害和利用性很低,通常只会泄露很少的用户信息。大多是利用来薅羊毛的。
  2. 攻击传输信道。攻击手段有中间人攻击,DNS劫持等。
  3. 攻击服务端。也非常难做到。一般是模板注入,撞库等。

这里面其实最容易的就是攻击传输信道。排除技术术语,手段有:

  1. 伪装成正常的客户端攻击服务端
  2. 伪装成正常的服务端,劫持客户端数据
  3. 监听修改信道数据

这几种怎么解决?

问:如何处理伪装成正常的客户端攻击服务端

在认为客户端app本身是无法攻破的前提下:

  1. 请求中一定加入签名策略。攻击者不知道签名策略是无法仿造请求的,也防止劫持者修改。发现签名不对,服务端认为是假的客户端。
  2. 请求中一定加入请求防重放策略。服务端发现是之前的请求,重复发送过来的(可能只有签名不一致),应该忽略
  3. 加入风险控制策略。比如异地登陆,同一设备ip反复请求,一些金融类app也会加入公安部认证的风控系统,防止一些有金融犯罪前科的用户注册。后端使用风控策略,禁止用户登录,或者强制要求用户再次身份认证,比如手机验证码认证。

问:如何处理监听修改信道数据
>

  1. 请求关键数据做加密,加密方案建议使用上面提到的加密方案。这样即使被监听,拿到数据也无法处理
  2. 加入请求签名,防止数据篡改。

问:如何处理伪装成正常的服务端,劫持客户端数据

这一种方式是目前攻击最常见且有效的手段。使用http的时候,因为没有任何认证措施,通过ARP或者DNS劫持,非常容易将网址定向到其他攻击者的地址,攻击者可以做劫持和修改相关数据。所以HTTP现在已经被各大平台所抛弃。很多开发遇到的访问一个h5页面,被运营商强插入广告就是这么做的。解决办法就是正确的使用HTTPS

HTTPS,很大一部分作用就是解决上述问题。也就是通过SSL握手,校验服务端证书,达到验证是否是伪装的服务端的目的。HTTPS握手阶段算法原理都是安全的,只有验证身份这一步有漏洞,即只要想办法让客户端认为证书是可信的,证书里面的公钥就是生成者的公钥,自然就有相对应的私钥,后面非对称加密生成的对称秘钥就可以被截取到,造成整个链路不安全。如何攻击这个策略,行业上主要称为中间人攻击

SSL证书

可以说验证SSL证书是整个HTTPS的关键,如果这一步出问题,后面的就没有任何安全可言。而对于我们前端开发来说,SSL证书也是最需要关注的地方。

这里讲两个问题。SSL证书是什么?为什么通过SSL证书可以防止攻击者伪装成服务端。

SSL证书是什么

SSL证书是一个文件。里面的内容包括:用户的信息、用户的公钥、还有CA中心对该证书里面的信息的签名。
一个证书的实例:

打开safari,打开百度,https://www.baidu.com,在地址栏点击锁按钮,然后选显示证书。

里面的内容只有几个需要关注的:

  1. 常用名称:baidu.com 。客户端或浏览器,根据常用名称和访问的域名做匹配,访问的域名和证书的域名不一致,就会拒绝访问,达到防止域名劫持的目的。这个信息可以被伪造。
  2. 公共密钥:SSL握手生成的第二段随机串是通过这个公钥来加密的。这个信息可以被伪造,但是伪造没有异议。(想知道为啥的可以看看证书生成的步骤。)
  3. 签名:是对整个证书内容做hash之后,使用颁发机构的私钥加密的值。这个信息可以被伪造,但是伪造没有异议。
  4. 签名者信息:颁发机构的信息,由于验证上一级的证书信息。这个信息可以被伪造。
  5. 证书有效期。这个信息可以被伪造。

可以看到在百度这个证书上面还有两个证书,这是因为百度这个证书是有GS这个机构的二级机构颁发的,而GS这个二级机构是由GS的CA根证书颁发的。

也就是证书有证书链的概念,即这个证书可能是上一层机构颁发的,从CA根证书开始->二级CA证书->三级CA证书->…。

注:来自SSL 之证书链

SSL证书如何验证的

推荐这篇文章,是目前看到讲的最清楚。浅析HTTPS中间人攻击与证书校验

根据HTTPS协议,服务端会在握手的时候将证书传送给客户单,而且是将整个证书链发过来

通常的验证传过来的证书是否有效的步骤为:

  1. 验证证书的常用名称是否是访问的域名,是否在有效期内。(域名校验+有效期校验)
  2. 计算这个证书内容的散列值得到MD5-a,然后用颁发机构的公钥解密这个证书的签名得到MD5-b,比较两个值是否相同,如果相同说明这个证书确实是上个颁发机构颁发的。
  3. 重复上面的操作,直到验证到CA根证书。CA证书是自签名的,也就是签名是用自己的私钥签名的。
    可是CA根证书签名是用自己的私钥做签名,怎么去验证这个证书是否正确呢?

最终上面的问题简化为:

如何验证CA根证书有效性

最终层层拨茧,HTTPS的安全性关键钥匙就在这一章了。

CA根证书有两种生成方式:

  1. 由可信的颁发机构颁发
  2. 本地自己生成

对于第一种,因为可信的颁发机构很少,这些机构的CA证书会默认保存在浏览器里或者手机操作系统里,由可信的机构颁发的证书的有效性会由颁发机构保证。不过这种证书需要向颁发机构申请,颁发机构会花时间去进行公司域名身份等信息验证,所以花费也不少。

对于第二种,本地生成的证书(后面会附录如何生成自签名证书),证书常用的信息都可以生成,可以认为证书信息内容都不可靠,尤其是证书中的域名。使用自制证书在浏览器会弹出警告不可信,用户可以手动添加到信任列表里,之后可信了才可以访问,12306之前让下载证书导入,就是这个原因。在应用APP里,如果使用默认配置,会拒绝,返回SSL验证失败。

在应用内信任自生成证书有两种办法:

第一种

安装描述文件到系统里。在安装charles过程中,其中一步就是打开一个网址,在弹出安装的时候,安装这个证书,也可以把这个证书下载到云盘里,然后打开。这个过程需要用户手动授权。这个起效后是全局的,任何应用都会影响。

第二种

把这个根证书,埋入APP里,然后设置为证书锚点(可以设置多个),然后在SSL握手需要验证证书的时候,系统会认为这个证书是有效的。这个方案也是很多自签名证书进行校验的方法。这个只会在本应用里起作用。

中间人攻击

中间人攻击是最常见的攻击HTTPS手段。

建议看这篇文章:iOS安全系列之二:HTTPS进阶

看到上面的验证手段,其实关键就在于如何信任CA根证书上面。攻击者就是想尽一切办法让客户端安装他自己的CA证书到你的手机里。

如果手机没有越狱,一定会引诱你去安装这个证书,并且手动设为可信。一旦信任,在访问服务器的时候,攻击者通过代理劫持,通过这个信任的CA证书,生成对应的域名的证书。最终因为域名可信,有效期可信,证书可信整个HTTPS建立成功,攻击者拿到相关的数据。

使用charles抓包的整个过程,其实就是中间人攻击的过程。

附:下面是charles开启SSL代理后,访问新浪弹出的证书信息,可以看到charles生成了新浪域名的证书:

提示:对于用户来说,不要信任任何CA证书,不安装任何描述文件是最安全的方法。比如安装飙车软件,让你信任一个证书。比如链接外部wifi,提示你安装证书才可以链接。比如翻墙设置代理,提示你安装信任证书。描述文件在通用->描述文件与设备管理中找到。

校验证书的姿势

校验证书有两种方案:

弱校验

对于服务端证书,校验下面的case。

  1. 校验证书的域名
  2. 校验证书的有效期
  3. 校验证书链和证书的有效性

保证这三者有效,已经可以解决大部分的攻击了。唯一的风险就是中间人攻击,被安装CA证书之后,一个被信任的CA根证书可以生成符合上面要求的任何域名的证书。存在着风险,但是攻击难度已经大大增加了。AFNetworking框架默认采用的就是这个策略

强校验

将证书放入APP中作为证书锚点。在上面的基础上再验证证书。这样可以完全保证服务端的证书是真正需要的证书,从而真正解决中间人攻击。

下面主要讲下强校验面临的坑,各位开发一定要注意。

证书强校验的坑

证书是有有效期的,尤其是非自制证书,通常都在三年以内(很多资料根本不谈这个问题)。一旦有效期过了,服务端就需要更换证书,但是由于APP存在发版的情况,老的APP由于所有链接失败,导致老APP任何请求都失效,然后无法通知用户更新,老用户也不知道因为什么访问失败。(这些都是血的教训啊)

有几个建议的地方:

  1. 尽量埋CA证书,因为CA证书的有效期要长,有足够的时间准备。
  2. 有些通道不要使用证书强校验,比如检查升级,一些热修复策略,尽量使用自有的安全逻辑保证安全。
  3. 如果是自制证书,建议有效期设置长一些。

上面的是尽量降低风险,该出问题的时候还是会出,有一些不完美的方案大家可以参考下:

方案1:动态更新证书。

在APP中放入RSA公钥,应用启动的时候,证书信息通过私钥加密,发送给前端保存,前端把这个新证书和埋入的证书一起做锚点,进行验证。这样可以保证老APP可以使用一段时间。缺点是这个下发的机制要尽量安全可靠,有可能被攻击者利用,而且后续的请求需要依赖这个请求,所以方案复杂一些。

方案2:只验证证书的公钥

只使用证书的公钥进行验证,因为更换证书,一般是通过.csr文件生成crt证书文件的(也就是证书文件),在.csr文件没变的情况下,生成的证书的公钥是一致的,也就即使服务端更换了证书,只要公钥不变,依然可以通过验证。所以验证公钥也是相对安全的。缺点是如果新的证书换了公钥还是出问题。我遇到的case就是需要更换私钥和证书算法,公钥也不一样了。

其他不太靠谱的方案:

方案3:

在弱校验的基础上,加上验证颁发机构。只要读到颁发机构是可信的,证书就认为是有效的。可以解决第三方抓包工具的抓包问题,因为第三方抓包工具,一般使用自己的颁发机构,和实际的颁发机构不一致。缺点是,证书是可以完全伪造的,包括颁发结构的名字,有效期等等都可以伪造。

方案4:

信任无效的证书。 信任无效的证书,但是做本地证书校验,在失效的一段时间内,后端先不部署新证书,在新版本里面提前埋入新证书,在几个版本后再上线新的证书。优点是简单,不怕哪天忘了更换证书导致出问题。缺点是信任失效的证书,如果真的有需求要强制更换证书,就没办法处理。

附录:

如何生成自签名证书

参考 深入解析HTTPS利用OpenSSL创建自签名的SSL证书自签名证书和私有CA签名的证书的区别 创建自签名证书 创建私有CA 证书类型 证书扩展名

  1. 生成私钥

    openssl genrsa -out ca.key 4096

  2. 利用私钥创建根证书

    openssl req -new -x509 -days 36500 -key ca.key -out ca.crt

    弹出的对话框按照提示填写:

    1
    2
    3
    4
    5
    6
    7
    Country Name (2 letter code) [AU]:CN
    State or Province Name (full name) [Some-State]:Guangdong
    Locality Name (eg, city) []:Shenzhen
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:BL.inc
    Organizational Unit Name (eg, section) []:
    Common Name (e.g. server FQDN or YOUR name) []:BL
    Email Address []:
  3. 创建SSL证书私钥

    openssl genrsa -out server.key 4096

  4. 使用刚才的私钥签名

    openssl req -new -key server.key -out server.csr

    弹出的对话框按照提示填写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Country Name (2 letter code) [AU]:CN
    State or Province Name (full name) [Some-State]:Guangdong
    Locality Name (eg, city) []:Shenzhen
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:BL.inc
    Organizational Unit Name (eg, section) []:
    Common Name (e.g. server FQDN or YOUR name) []:*.sina.com.cn
    Email Address []:
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:1111
    An optional company name []:

    注意,这里的Common Name 应该和实际的域名匹配。而且生成的.csr这个文件最好长期保留,下次过期的时候,建议直接用这个文件做签名。如果是向CA颁发机构申请,提交的文件也是这个文件。

  5. 对上一步的csr使用CA进行签名生成证书

    openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

    如果是向CA机构申请,提交这个文件就可以了。

  6. 如果有必要可以重复上面必要步骤,使用上一步的证书的.crt和.key继续签名下一级证书。

    一些常用命令:

    1
    2
    3
    4
    5
    openssl s_client -connect www.google.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > https.cer //获取www.google.com:443的ssl证书,地址可以换成自己的
    openssl rsa -noout -text -in server.key 查看私钥信息
    openssl req -noout -text -in server.csr 查看签名请求信息
    openssl x509 -noout -text -in ca.crt 查看证书信息

MAC下使用Charles抓包

参考 深入解析HTTPSiOS安全系列之二:HTTPS进阶

  • 安装Charles CA根证书

    点击Help->SSL Proxying->Install Charles Root Certification …,会弹出如下提示,链接代理,手机浏览器输入chls.pro/ssl,就可以安装根证书了。

  • 设置SSL代理

    点击Proxy->SSL Proxying Setting,勾选Enable SSL Proxying,然后点击Add输入要SSL代理的请求Host和Port,可以使用通配符来表示某一类请求。

    或者在对应的请求上右键选择Enable SSL Proxying,就会把这一个请求加入到上面的SSL代理列表中(类似于点击Add的效果)。

    做完上述步骤后重新请求就能得到解密后的信息了。ps:抓取PC端的HTTPS包也类似,在Help->SSL Proxying中下载证书,双击安装证书,并选择始终信任即可。

  • 在iPhone端设置HTTP代理

    在Mac上获取当前机器的IP地址:

    ifconfig en0:

    ch将iPhone连接到与电脑相同的WiFi,在iPhone设置中:无线局域网 -> 已连接WiFi右边的Info详情图标 -> HTTP代理 -> 手动 -> 设置HTTP代理:

    设置完成之后,打开Safari随便访问一个网页,初次设置代理的话,Charles会弹出一个iPhone请求代理的确认框,点击Allow即可。然后在Charles上就可以看到iPhone上的HTTP请求了。为了避免Mac上的请求过多影响对被代理iPhone上HTTP请求的查看和调试,可以在Charles取消Mac的代理:Menu -> Proxy -> 取消勾选Mac OS X Proxy 即可。

参考文献

  1. HTTP协议详解(真的很经典)

  2. MQTT_github

  3. 说说http协议中的编码和解码

  4. HTTP协议之multipart/form-data请求分析

  5. 苹果文档翻译 iOS10 NSAppTransportSecurity

  6. iOS中的HTTPS, 你知道多少?

  7. 阮一峰:图解SSL/TLS协议

  8. SSL与TLS的区别以及介绍

  9. 浅析HTTPS中间人攻击与证书校验

  10. SSL、TLS协议格式入门学习 - .Little Hann

  11. iOS安全系列之二:HTTPS进阶

  12. HTTPS 理论详解与实践

  13. 利用OpenSSL创建自签名的SSL证书

  14. 自签名证书和私有CA签名的证书的区别 创建自签名证书 创建私有CA 证书类型 证书扩展名

  15. 深入解析HTTPS

  16. TLS/SSL 高级进阶

坚持原创技术分享,您的支持将鼓励我继续创作!