写点什么

Android10 版本引发的生产故障及安全知识归纳

用户头像
大刘
关注
发布于: 2020 年 05 月 14 日
Android10版本引发的生产故障及安全知识归纳

生产环境的 bug

公司产品线有一项业务基于 Android 手机 APP 的,前段时间发了一个故障,故障现象:所有 Android10 的手机都无法连接到后台服务器了,Android9 及以下的都没有问题。经过一系列的排查,发现问题出现在 TLS 协议版本上。最终是解决了问题,在这次解决问题的过程中,也梳理了安全连接相关的知识点,在这里做个归纳总结,希望对自己和遇到同类问题的朋友有所帮助。


系统架构:前端连接比较简单,就是 android 通过互联网连接到 F5 做负载均衡,然后转发到 Tomcat 的应服务器上,在 Tomcat 上启用了 https 的单向认证,然后 Android APP 里有一个客户端证书,连接的时候去验证服务器端证书。类似这样:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" SSLEnabled="true" maxThreads="24" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" SSLCertificateFile="server.pem" />
复制代码


从报错信息来看,是说签名算法被加入了黑名单,然后查阅了 android10 的升级文档,发现有如下说明:

默认启用 TLS 1.3 - Android 10 还默认启用 TLS 1.3,它是 TLS 标准的主要修订版本,具有性能优势和更高的安全性。

TLS 不信任使用 SHA-1 签名的证书

在 Android 10 中,使用 SHA-1 哈希算法的证书在 TLS 连接中不受信任。自 2016 年以来,根 CA 未再颁发过此类证书,因为它们不再受 Chrome 或其他主流浏览器的信任。

如果某网站使用的是 SHA-1 证书,则任何尝试连接该网站的操作都将失败。

https://developer.android.google.cn/about/versions/10/behavior-changes-all#tls-1.3


那这样基本就对的上了,我们的系统是在 5 年前上线的,当时使用的 JDK1.6 自带的 keytool 去制作的服务器证书,然后去机构 CA 进行的签名,默认就是生成的 sha1WithRSAEncryption 算法,从 JDK1.7 之后在生成证书,默认的签名算法就是 sha256WithRSAEncryption 了。

keytool -genkey -alias server -keyalg RSA -keysize 2048 -dname "CN=***" -keystore server.jks
复制代码


从 Android 源代码来看,也符合上述的描述:

Android9 源代码:


Android10 源代码:


所以最终的解决方法,就是对服务器证书重新进行制作,然后用 CA 重新进行签发,签发过程中指定为 sha256WithRSAEncryption 的签名算法,客户端的公钥不需要变(因为 CA 并没有改变)。

知识整理

在解决问题的过程中,查阅了很多资源,特别是之前在极客时间购买的教程里,有目的性的再去学习专栏里的某篇文章,效果更好,理解更深,也在此做个梳理。

加解密的方式

加解密的方式,主要分为对称加密、非对称加密、哈希算法(也叫摘要算法、散列算法)

  1. 对称加密:

加密和解密密钥是相同的。通信方必须具有相同的密钥才能实现安全通信。对称密钥的一个典型例子:德国军方的恩尼格玛密码机。这种密码机每天都有密钥设置。当盟军弄清楚机器如何工作时,他们能够在发现给定日期传输的加密密钥后立即解密消息中编码的信息。

常用的算法有:RC4、DES、3DES、AES 以及 Salsa20、ChaCha20、Camellia 等


  1. 非对称加密:

它需要两个密钥,一个是公开密钥,另一个是私有密钥;公钥用作加密,私钥则用作解密。使用公钥把明文加密后所得的密文,只能用相对应的私钥才能解密并得到原本的明文,最初用来加密的公钥不能用作解密。由于加密和解密需要两个不同的密钥,故被称为非对称加密;不同于加密和解密都使用同一个密钥的对称加密。公钥可以公开,可任意向外发布;私钥不可以公开,必须由用户自行严格秘密保管,绝不透过任何途径向任何人提供,也不会透露给被信任的要通信的另一方。

常用的算法有:RSA、Diffie-Hellman、DSA、ECDSA、ECDH 等


我们平时常说的签名算法,其实也是非对称加密的一种。数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,而在数字签名中,是私钥加密、公钥解密。但又因为非对称加密效率太低,所以私钥只加密原文的摘要,这样运算量就小的多,而且得到的数字签名也很小,方便保管和传输。下面是维基百科上关于签名验签的一个简化图示:


  1. 哈希:

它是一种将任意长度的数据转化为固定长度的算法,哈希算法是不可逆的。

常用算法有:MD5、SHA1、SHA256 以及 SHA384。


目前还有国密算法,为了保障商用密码的安全性,国家商用密码管理办公室制定了一系列密码标准,包括 SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、祖冲之密码算法(ZUC)那等等。

其中 SM1、SM4、SM7、祖冲之密码(ZUC)是对称算法;SM2、SM9 是非对称算法;SM3 是哈希算法。

HTTPS 协议

说完了加密方式和算法,再说 HTTPS 协议,以前在生产系统也经常受到安全漏洞报警,例如:SSLv3 POODLE。然后我们对 tomcat 进行了升级,修复策略也就是:修改 Tomcat 的配置文件,使其禁用 SSLv3 协议。


漏洞描述:SSL3.0 是已过时且不安全的协议,目前已被 TLS 1.0,TLS 1.1,TLS 1.2 替代,因为兼容性原因,大多数的 TLS 实现依然兼容 SSL3.0。此漏洞影响绝大多数 SSL 服务器和客户端,影响范围广泛。

漏洞危害:若受到 POODLE 攻击,攻击者可以在网络上窃取传输的数据。

风险等级:中风险


  1. 关于 HTTPS 协议:

为什么要有 HTTPS?简单的回答是“因为 HTTP 不安全”。由于 HTTP 天生“明文”的特点,整个传输过程完全透明,任何人都能够在链路中截获、修改或者伪造请求 / 响应报文,数据不具有可信性。


在将 HTTP 数据提交给 TCP 层之后,数据会经过用户电脑、WiFi 路由器、运营商和目标服务器,在这中间的每个环节中,数据都有可能被窃取或篡改。比如用户电脑被黑客安装了恶意软件,那么恶意软件就能抓取和篡改所发出的 HTTP 请求的内容。或者用户一不小心连接上了 WiFi 钓鱼路由器,那么数据也都能被黑客抓取或篡改。


鉴于 HTTP 的明文传输使得传输过程毫无安全性可言,且制约了网上购物、在线转账等一系列场景应用,于是我们要引入加密方案。从 HTTP 协议栈层面来看,我们可以在 TCP 和 HTTP 之间插入一个安全层,所有经过安全层的数据都会被加密或者解密,可以参考下图:

通常认为,如果通信过程具备了四个特性,就可以认为是“安全”的,这四个特性是:机密性、完整性,身份认证和不可否认。https 协议加上数字证书,也就保证上述通讯过程的安全性。


  1. 关于 SSL/TLS 协议:

SSL 即安全套接层(Secure Sockets Layer),在 OSI 模型中处于第 5 层(会话层),由网景公司于 1994 年发明,有 v2 和 v3 两个版本,而 v1 因为有严重的缺陷从未公开过。SSL 发展到 v3 时已经证明了它自身是一个非常好的安全通信协议,于是互联网工程组 IETF 在 1999 年把它改名为 TLS(传输层安全,Transport Layer Security),正式标准化,版本号从 1.0 重新算起,所以 TLS1.0 实际上就是 SSLv3.1。到今天 TLS 已经发展出了三个版本,分别是 2006 年的 1.1、2008 年的 1.2 和去年(2018)的 1.3,每个新版本都紧跟密码学的发展和互联网的现状,持续强化安全和性能,已经成为了信息安全领域中的权威标准。目前应用的最广泛的 TLS 是 1.2,而之前的协议(TLS1.1/1.0、SSLv3/v2)都已经被认为是不安全的,各大浏览器即将在 2020 年左右停止支持。


关于 TLS 版本的支持,可以参考维基百科的内容:

TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等许多密码学前沿技术。浏览器和服务器在使用 TLS 建立连接时需要选择一组恰当的加密算法来实现安全通信,这些算法的组合被称为“密码套件”(cipher suite,也叫加密套件)。


另外需要说明的是,TLS 协议并不是只能和 http 协议组合的。除了 HTTP 之外,SSL/TLS 协议也可以应用到其他的协议之上,例如 FTP、LDAP、SMTP 等等。


  1. HTTPS 握手过程:

在了解了名词解释之后,就要看 HTTPS 的握手过程了。关于握手过程,看了很多 Blog,其中刘超老师在极客时间的这篇教程里描述的很形象,推荐阅读:HTTPS协议:点外卖的过程原来这么复杂

借用图如下:

整个过程刘超老师的描述如下:

当你登录一个外卖网站的时候,由于是 HTTPS,客户端会发送 Client Hello 消息到服务器,以明文传输 TLS 版本信息、加密套件候选列表、压缩算法候选列表等信息。另外,还会有一个随机数,在协商对称密钥的时候使用。

这就类似在说:“您好,我想定外卖,但你要保密我吃的是什么。这是我的加密套路,再给你个随机数,你留着。”

然后,外卖网站返回 Server Hello 消息, 告诉客户端,服务器选择使用的协议版本、加密套件、压缩算法等,还有一个随机数,用于后续的密钥协商。

这就类似在说:“您好,保密没问题,你的加密套路还挺多,咱们就按套路 2 来吧,我这里也有个随机数,你也留着。”

然后,外卖网站会给你一个服务器端的证书,然后说:“Server Hello Done,我这里就这些信息了。”

你当然不相信这个证书,于是你从自己信任的 CA 仓库中,拿 CA 的证书里面的公钥去解密外卖网站的证书。如果能够成功,则说明外卖网站是可信的。这个过程中,你可能会不断往上追溯 CA、CA 的 CA、CA 的 CA 的 CA,反正直到一个授信的 CA,就可以了。

证书验证完毕之后,觉得这个外卖网站可信,于是客户端计算产生随机数字 Pre-master,发送 Client Key Exchange,用证书中的公钥加密,再发送给服务器,服务器可以通过私钥解密出来。

到目前为止,无论是客户端还是服务器,都有了三个随机数,分别是:自己的、对端的,以及刚生成的 Pre-Master 随机数。通过这三个随机数,可以在客户端和服务器产生相同的对称密钥。

有了对称密钥,客户端就可以说:“Change Cipher Spec,咱们以后都采用协商的通信密钥和加密算法进行加密通信了。”

然后发送一个 Encrypted Handshake Message,将已经商定好的参数等,采用协商密钥进行加密,发送给服务器用于数据与握手验证。

同样,服务器也可以发送 Change Cipher Spec,说:“没问题,咱们以后都采用协商的通信密钥和加密算法进行加密通信了”,并且也发送 Encrypted Handshake Message 的消息试试。当双方握手结束之后,就可以通过对称密钥进行加密传输了。

这个过程除了加密解密之外,其他的过程和 HTTP 是一样的,过程也非常复杂。

上面的过程只包含了 HTTPS 的单向认证,也即客户端验证服务端的证书,是大部分的场景,也可以在更加严格安全要求的情况下,启用双向认证,双方互相验证证书。


简单来讲有下面几个重点:

  1. HTTPS 协议会先与服务器执行 TCP 握手,然后执行 TLS 握手,才能建立安全连接;

  2. 握手的目标是安全地交换对称密钥,需要三个随机数,第三个随机数“Pre-Master”必须加密传输,绝对不能让黑客破解;

  3. “Hello”消息交换随机数,“Key Exchange”消息交换“Pre-Master”;

  4. “Change Cipher Spec”之前传输的都是明文,之后都是对称密钥加密的密文。

动手实践

看完上面的知识点,就可以动手验证一下了,以极客时间的网址为例,先ping time.geekbang.org获取 IP 地址,然后使用 wireshark 进行抓包,截图如下:

可以看到,握手过程有 Client Hello、Server  Hello、Server hello Done、Key Exchange、Change Cipher Spec 这几个阶段。然后下面的详细信息就是在 Client Hello 阶段,发送的密码套件(cipher suite)等。


以上就是根据这次生产故障的解决过程而整理出来的一些知识点了,后续关于安全,还有很多值得整理的东西,例如数字证书的概念和原理,keytool 和 openssl 的使用方法和区别等,一边学习一边归纳总结吧。


第一次使用 InfoQ 的写作平台,挺好用的,希望这个是继极客时间之后,又一个成功的产品大作。


发布于: 2020 年 05 月 14 日阅读数: 94
用户头像

大刘

关注

大道至简,知易行难 2017.12.27 加入

想成为合格架构师的架构师

评论 (1 条评论)

发布
用户头像
内容很不错,排版可以加一下空行,视觉上更清晰
2020 年 05 月 14 日 17:01
回复
没有更多了
Android10版本引发的生产故障及安全知识归纳