欢迎光临
专注android技术,聚焦行业精粹,我们一直在努力

Https安全性探究和Android接入的正确姿势

  1. 更全面了解https的安全机制,漏洞,以及常听到的双向认证、单向认证、数字证书、数字签名的到底是什么
  2. 更实用文章的最后有android详细的接入示例,方便开发者快速实现自己的安全的https逻辑

1、Https 介绍

https简单的说就是安全版的http,因为http协议的数据都是明文进行传输的,所以对于一些敏感信息的传输就很不安全,为了安全传输敏感数据,网景公司设计了SSL(Secure Socket Layer),在http的基础上添加了一个安全传输层,对所有的数据都加密后再进行传输,客户端和服务器端收到加密数据后按照之前约定好的秘钥解密。

1.1、客户端与服务器的交互流程

流程图:

流程介绍:

1、客户端(通常是浏览器)先向服务器发出加密通信的请求

请求中包含的信息:

(1) 支持的协议版本,比如TLS 1.0版。
(2) 一个客户端生成的随机数 random1,稍后用于生成”对话密钥”,即服务端和客户端通信的AES key
(3) 支持的加密方法,比如RSA公钥加密。
(4) 支持的压缩方法。

2、服务器收到请求,然后响应

服务端response返回参数:

(1) 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
(2) 一个服务器生成的随机数random2,稍后用于生成”对话密钥”,即服务端和客户端通信的AES key
(3) 确认使用的加密方法,比如RSA公钥加密。
(4) 服务器证书。

3、客户端对服务端单向认证(认证服务端的证书是否可信任)

a) 我们知道CA机构在签发证书的时候,都会使用自己的私钥对证书进行签名
证书里的签名算法字段 sha256RSA 表示,CA机构使用sha256对证书进行摘要,然后使用RSA算法对摘要进行私钥签名,而我们也知道RSA算法中,使用私钥签名之后,只有公钥才能进行验签。

b) 如果我们使用的是购买的证书,那么很有可能,颁发这个证书的CA机构的公钥已经预置在操作系统中。这样浏览器就可以使用CA机构的公钥对服务器的证书进行验签,以确定这个证书是不是由正规的CA机构颁发的。验签之后得到CA机构使用sha256得到的证书摘要,然后客户端再使用sha256对证书内容进行一次摘要,如果得到的值和验签之后得到的摘要值相同,则表示证书没有被修改过。

c) 在浏览器上如果验证通过,会显示安全字样,如果服务器购买的证书是更高级的EV类型,就会显示出购买证书的时候提供的企业名称。如果没有验证通过,就会显示不安全的提示。

4、客户端生成pre-master secet通过公钥加密后传递给服务器,用于后面生成客户端与服务器通信的AES key

验证通过之后,客户端会生成一个随机数pre-master secret,然后使用证书中的公钥进行加密,然后传递给服务器端

什么时PreMaster secret?

PreMaster Secret是在客户端使用RSA或者Diffie-Hellman等加密算法生成的。它将用来跟服务端和客户端在首次请求和响应阶段产生的随机数(即上面提到的random1和random2)结合在一起生成 Master Secret(即服务端与客户端通信的AES key)。在客户端使用服务端的公钥对PreMaster Secret进行加密之后传送给服务端,服务端将使用私钥进行解密得到PreMaster secret。也就是说服务端和客户端都有一份相同的PreMaster secret和随机数。
PreMaster secret前两个字节是TLS的版本号,这是一个比较重要的用来核对握手数据的版本号,因为在Client 首次请求和响应阶段,客户端会发送一份加密套件列表和当前支持的SSL/TLS的版本号给服务端,而且是使用明文传送的,如果握手的数据包被破解之后,攻击者很有可能串改数据包,选择一个安全性较低的加密套件和版本给服务端,从而对数据进行破解。所以,服务端需要对密文中解密出来对的PreMaster版本号跟之前Client Hello阶段的版本号进行对比,如果版本号变低,则说明被串改,则立即停止发送任何消息。

 

Diffie-Hellman 算法 来保证Premaster secret不被破解

上面讲了 SSL 协议的握手过程中通过随机数生成AES key,由于握手交换随机数的过程是不加密的,因此,如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(Premaster secret)能不能被破解。

虽然理论上,只要服务器的公钥足够长(比如2048位),那么Premaster secret可以保证不被破解。但是为了足够安全,我们可以考虑把握手阶段的算法从默认的RSA算法,改为 Diffie-Hellman算法(简称DH算法)。

采用DH算法后,Premaster secret不需要传递,双方只要交换各自的参数,就可以算出一个相同的会话密钥。

Diffie-Hellman 算法把传递 PreMaster Secret 变成了传递 DH parameter。然后服务器和客户端根据 DH parameter 计算得出一个相同的会话密钥。

 

5、服务器收到使用公钥加密的内容,在服务器端使用私钥解密之后获得随机数pre-master secret,然后根据radom1、radom2、pre-master secret通过一定的算法得出session Key和MAC算法秘钥,作为后面交互过程中使用对称秘钥。同时客户端也会使用radom1、radom2、pre-master secret,和同样的算法生成session Key和MAC算法的秘钥。

通过以上几个步骤服务端和客户端都已经有了相同的密钥key,这个密钥key会用作接下来对传输数据的AES 加密密钥了。

小知识点:

公钥和私钥都可以用来加密数据,经过私钥加密的数据,只有通过公钥才可以解密出来,反之亦然。

2、Https 安全

总结来说https的安全是通过 对称加密 + 非对称加密 + CA认证 这三个技术混合在一起,才使得 HTTP 的后面加上了一个 S —— Security。

然而不正确的使用会导致https不安全,例如现在很多android客户端在加载一个https的网页时,或者本地请求一个https的服务端url时没有正确的校验服务端的CA证书(即没有满足https中的CA认证这一安全点),导致看似使用了安全的https,其实形同虚设。利用常说的“中间人”漏洞就可以轻松破解。

这一节会介绍什么是“中间人”漏洞,CA认证技术中常说的单向认证双向认证是啥,CA(即数字证书)认证的原理:

2.1、中间人漏洞

Man-in-the-middle(中间人,简称为 MITM),能够与网络通讯两端分别创建连接,交换其收到的数据,使得通讯两端都认为自己直接与对方对话,事实上整个会话都被中间人所控制。简而言之,在真正的服务端看来,中间人是客户端;而真正的客户端会认为中间人是服务端。

示例如下:

也就是说如果客户端没有对服务端校验,那么就很容易把中间人认为就是目标服务端。而服务端没有对客户端校验,那么服务端同样认为中间人为目标客户端。实际应用场景中,我们一定需要认证服务端,这样能有效避免中间人漏洞,而只有一些非特殊场景服务端不会认证客户端,因为大多数服务端会接受任何客户端的请求。有一些场景会认证客户端,举个例子,支付宝网站会为不同的客户端生成不同的证书,例如你家里有台电脑,公司有台电脑,支付宝会为你生成对应的两个证书,用于支付时的客户端认证,目的是为了保证用户的账号没有被盗用,所以需要校验用户的身份。

2.2、单向认证

以上是单向认证的完整流程,单向认证是客户端认证服务端。

2.3、单向认证(服务端CA认证)的原理

从https的交互流程我们知道在第一次握手的时候服务器会返回服务端的“数字证书”给到客户端,服务端的“数字证书”生成过程如下:

数字签名:是用来验证数据完整性的,首先将公钥与个人信息用一个Hash算法生成一个消息摘要,Hash算法是不可逆的,且只要内容发生变化,那生成的消息摘要将会截然不同。CA再用它的私钥对消息摘要加密,最终形成数字签名

数字证书:拿到数字签名后,还把原始信息和数据签名合并,形成一个全新的东西,叫做“数字证书”

通常服务端不会自己去生成一个数字证书,而是通过CA来做的。

CA中心又称CA机构,即证书授权中心(Certificate Authority ),或称证书授权机构,作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。

服务端申请认证的过程如下:

  1. 申请认证:服务器需自己生成公钥私钥对pub_svr & pri_svr,同时根据 pub_svr 生成请求文件 csr,提交给CA,csr中含有公钥、组织信息、个人信息(域名)等信息
  2. 审核信息:CA通过线上、线下等多种手段验证申请者提供信息的真实性,如组织是否存在、企业是否合法,是否拥有域名的所有权等。
  3. 签发证书:如信息审核通过,CA会向申请者签发认证文件-证书。
    证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构 CA的信息、有效时间、证书序列号等信息的明文,同时包含一个签名。
    数字签名的产生算法:首先,使用散列函数计算公开的明文信息的信息摘要,然后,采用 CA的私钥对信息摘要进行加密,密文即数字签名。
  4. https第一次握手返回证书:https第一次握手时服务端会返回服务端的数字证书,这个证书就是服务端申请的数字证书。
  5. 客户端认证服务器:client读取证书中的相关的明文信息,采用相同的散列函数计算得到信息摘要,然后,利用对应 CA的公钥解密签名数据,对比证书的信息摘要,如果一致,则可以确认证书的合法性,即公钥合法。客户端然后验证证书相关的域名信息、有效时间是否吊销等信息。 但这里有个问题我们如何找到对应CA的公钥,其实不管是PC端还是android客户端,系统都会内置信任CA的证书信息(包含公钥),如果找不到对应 CA的证书,那么可以断定该CA不被信任,则证书也会被判定非法。

2.3.1、CA证书的信用体系

CA证书的信用体系像一棵树的结构,上层节点是信用高的CA同时它也会对底层的CA做信用背书(信用担保),操作系统(例如Android系统)/浏览器中会内置一些顶层的CA的证书,相当于你自动信任了他们。这样通过各级实体证书的验证,逐渐上溯到链的终止点,即可信任的根CA,如果到达终点在自己的信任列表内未发现可信任的CA则认为此证书不可信。

引用高性能网络中的证书链校验图,验证证书链的时候,用上一级的公钥对证书里的签名进行解密,还原对应的摘要值,再使用证书信息计算证书的摘要值,最后通过对比两个摘要值是否相等,如果不相等则认为该证书不可信,如果相等则认为该级证书链正确,以此类推对整个证书链进行校验。

2.4、双向认证

上面图中红色文字标记了双向认证和单向认证不同的地方,主要有两点:

  1. 客户端校验完服务端后需要将自己的证书和公钥给到服务端,服务端校验客户端是否合法
  2. 服务端将将选择好的加密方案不是以明文的方式给到客户端,而是用客户端的公钥加密后给到客户端

2.4.1、服务端认证客户端的方式

服务器端通过根CA给客户端颁发客户端证书,在制作客户端证书时加上和机器相关的信息就可以保证在特定的时候某个帐号只能在这台机器上和服务器交换报文,比如我们用支付宝时必须下载安装数字证书时,可以命名这本证书叫”我的笔记本”或者是”公司电脑”之类的,就是支付宝给用户颁发证书,只能在这台机器上用,你换了机器就必须重新申请。建立SSL连接时,先是服务器将自己的服务器证书发给客户端,验证通过后,客户端就把自己的客户端证书发给服务器进行验证,如果通过,再进行后面的处理。

3、Android 接入https的正确姿势

从上面大篇幅的文章我们知道https里面最关键的环节是认证,没有了认证,https的安全机制就形同虚设,毫无安全可言,这也是为什么android不建议我们信任所有证书做法的原因,官方的对开发者的建议如下:

正确的姿势是我们得构建一个有效的TrustManager,为了达到这个目的我们的服务器的请求地址要么有CA权威机构认证的证书,如果没有(国内大多数业务场景不会有CA认证的证书)那么客户端要拿到服务器自己生成的证书文件。拿到这个文件后可以把它放在apk包里面,也可以放在私有目录等安全的地方,然后在代码中通过流的方式读出来。一种更简单的方式是将CA的字节流base64后得到一个字符串然后保存在任意位置,也可以是代码里面。具备了这些我们就可以开始写https代码了。

先看下android https相关的类图:

这张图有3个重要的角色:Certificate, TrustManager, SSLContext

Certificate: 存放CA证书信息

TrustManager: TrustManagers负责管理在做出信任决策时使用的信任材料,以及决定是否接受对等方提供的凭证。

SSLContext: 此类的实例表示安全套接字协议实现,它充当安全套接字工厂或SSLEngines的工厂。 该类使用一组可选的密钥和信任管理器以及安全随机字节源进行初始化。

3.1、接入代码示例

1、通过CA证书源文件生成对应的TrustManager

很多时候我们的业务服务器没有从正规的CA机构申请得到数字证书,而且这种方式对于当前快速迭代的业务也是不现实的。所以服务器会自己生成证书丢给客户端,然而这样的证书用系统内置的证书是无法识别的,所以我们需要自己通过这个证书构建一个自己的TrustManager, 这个TrustManager只信赖我们给的证书,那么就实现了https中重要的环节——服务端认证。这样有效的避免了“中间人漏洞”的问题。

2、使用上面的TrustManager生成SSLContext

该SSLContext我们除了使用上面自定义的TrustManager,我们还用到了默认的TrustManager,该默认的TrustManager作为最终兜底处理。同时我们的SSLContext只处理的服务端认证,保证客户端正在通信的不是中间人。

3、OkHttp 接入

构建一个OkhttpClient

 

赞(0) 打赏
未经允许不得转载:花花鞋 » Https安全性探究和Android接入的正确姿势
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

国内精品Android技术社区

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏