如何理解HTTPS的安全校验
关于Htpp的安全性大家都有了解,目前最流行的HTTP1.1使用了明文传输协议,传输的数据都是明文可见的,其安全性无法保障,由此诞生了HTTPS。HTTPs从协议上依旧是HTTP的协议,并不是一个新的协议,只不过在HTTP的应用层之下加了一层SSL(TLS)协议,HTTPS=HTTP+SSL/TLS
Htpp1与Https和Http2结构区分.jpeg在理解HTTPS的安全校验机制前需要讲下几个基础点:加密解密与签名验证、数字签名、数字证书
1. 加密解密与签名验证
现代密码学中加密与解密的方式主要有两种:对称加密和非对称加密。两者的区别我们对比分析讲解下
-
对称加密
通信双方使⽤同⼀个密钥,使⽤加密算法配上密钥来加密,解密时使用加密过程逆过程配合密钥来进⾏解密
对称加密.png
优点:对称加密算法相对于非对称加密算法简单,速度快。
缺点:在不安全的网络环境下传输一旦泄露密钥则加密通信即被破解
破解思路:穷举法进行寻找一个密钥,将原文进行加密 反之进行解密:
反破解的思路:优秀的加密算法使得破解者找不到暴力破解的更有效的方法,但需要暴力破解的时间非常长(例如上百年)
-
非对称加密
使⽤公钥对数据进⾏加密得到密文;使⽤私钥对数据进行解密得到原数据,它与对称加密的不同在于两个密钥,并且非对象加密只在现代密码学中出现,它并非像对称密码算法是由古代密码学演进而来
非对称加密.png
优点:相对对称加密而言,它可以在不可信的网络上将双方的公钥传给对方,双方发消息时只要使用公钥 加密即可,接收方使用私钥进行解密
缺点:算法复杂,算法实现性能上相对对称加密比较差
另外非对称加密算法要求一个公钥只有一个私钥
非对称加密关键是私钥,公钥可以对外开放提供,但私钥万万不能提供出去,因为利用椭圆曲线算法可以通过私钥计算出公钥,但公钥无法计算出私钥
由于非对称加密中的公钥和私钥是互相可解的,因此衍生出数字签名和验证
-
签名与验证
简化版签名与验证.png与非对称加密解密相反,使用私钥对数据A进行运算处理生成数据B这个步骤叫签名,
完整版签名与验证.png
而使用公钥对数据B进行运算处理生成数据A叫做验证,既然是验证,那就需要和原数据进行对比,由此证明签名的正确性
由于原数据可能是非常大的数据(比如几个G),对此进行签名也是非常耗资源和性能的,由此提出Hash摘要处理,通过Hash摘要进行签名,大大减少了资源和性能的开销
2.数字证书
服务器与客户端进行加密通信的时候,服务器需要向客服端进行发送证书以证明自己,但这个证书是什么呢?它由谁发放?为什么相信这个证书能证明服务器自己呢?
证书.png上图就是一个证书的简略版本,其内带有详细的数据,我们为了简述它的运行机制暂只将有用的数据进行表述
- 蓝色是服务器发放到客户端的证书,它包括了服务器的地址,证书的公钥和证书的签名,其数据已经被证书的发放机构进行了私钥签名
- 黄色的是证书机构数据,其包括了证书机构的其他数据和公钥,此公钥即可解密蓝色数据,但我们怎么证明这个数据就是可信的真实数据呢?我们继续往上看
- 深蓝色的数据是证书机构的签发方,如果保证了签发方的正确,那其也就能保证二级机构数据的准确性,也就能保证三级服务器证书的正确性
最后归根结底我们如何来证明签发方的正确性呢?其答案就和我们操作系统有关了,操作系统在最初始阶段就会将这些跟证书编译到系统中去,这些证书是由操作系统对各证书签发方进行验证才归入到系统中的。
3.HTTPS握手(TLS)安全验证-单向验证
tls握手.png- Client Hello --客户端向服务器申请建立链接
在申请时将客户端产生的随机数client_random
、TLS版本、加密套件传给服务端。其加密套件内包含:对称加密算法、非对称加密算法、Hash算法,一般会长的像下面这样
TLS_ECDHE_WITH_AES_128_GCM_SHA256
1. TLS握手过程中,使用ECDHE算法生成pre_random
2. 128位的AES算法进行对称加密,在对称加密的过程中使用主流的GCM分组模式
3. 采用SHA256 hash摘要算法
-
Server Hello --服务器确认并返回客户端数据
服务端收到客户端的请求后,也进行了数据的确认,比如选择同TLS版本通信,设置和客户端一致的加密套件,并且也随机产生一个随机数server_random
,这s时服务端就拥有了client_random
和server_random
两个随机数 -
Server Hello Done-向客户端下发证书,通知客户端 Server Hello 过程结束
客户端收到服务端传来的证书后,先从CA验证该证书的合法性,验证通过后取出证书中的服务端公钥,再生成一个随机数Random3,再用服务端公钥非对称加密 Random3 生成 PreMaster 这个地方是全程唯一一次使用非对称加密,后面通信用对称加密沟通 -
将premaserkey传给服务器,服务器利用非对称加密进行解密获得Random3
到这一步客户端和服务器都有了client_random
、server_random
、Random3
三个随机数
客户端和服务器两边再根据同样的算法就可以生成一份密钥,握手结束后的应用层数据都是使用这个密钥进行对称加密 -
Client Finish 客户端会先后发两个数据给服务端:
- 事件消息:客户端通知服务端后面再发送的消息都会使用前面协商出来的密钥加密
- 客户端将事件消息生成摘要再用协商好的密钥加密,这是客户端发出的第一条加密消息。服务端接收后会用密钥解密,能解出来说明前面协商出来的密钥是一致的。
-
Server Finish :服务器同样也会发两个数据给客户端:
- 事件消息 服务端通知客户端后面再发送的消息都会使用加密
- 服务端也会将事件消息生成摘要再用密钥加密,这是服务端发出的第一条加密消息。客户端接收后会用密钥解密,能解出来说明协商的密钥是一致的。
到此整个的安全校验就已经结束了。
4如何使用HTTPS
目前对于TLS的握手交互我们已经了解整个过程,在第三步中用到的证书其实有自己的证书体系
4.1 证书体系
针对HTTPS中的证书,有专门的管理体系PKI,按照官方对PKI的定义:
pki架构.png公钥基础设施是一个包括硬件、软件、人员、策略和规程的集合,用来实现基于公钥密码体制的密钥和证书的产生、管理、存储、分发和撤销等功能
PKI意义上就是将证书的管理进行标准化,核心是对证书的分发和生命周期管理
公钥存储在数字证书中,标准的数字证书一般由可信数字证书认证机构(CA,根证书颁发机构)签发,此证书将用户的身份和公钥链接在一起。CA必须保证其签发的每个证书的用户身份是唯一的。
链接关系(证书链)通过注册和发布过程创建,取决于担保级别,链接关系可能由CA的各种软件或在人为监督下完成。
PKI的确定链接关系的这一角色称为注册管理中心(RA,也称中级证书颁发机构或者中间机构)。RA确保公钥和个人身份链接。如果没有RA,CA的Root 证书遭到破坏或者泄露,由此CA颁发的其他证书就全部失去了安全性,所以现在主流的商业数字证书机构CA一般都是提供三级证书,Root 证书签发中级RA证书,由RA证书签发用户使用的证书。
X509证书链,左边的是CA根证书,中间的是RA中间机构,右边的是用户
X509证书链.png官方CA下发证书
官方CA.png由于使用官方证书是需要费用的,所以许多网站使用非官方可信CA证书,对于非可信CA证书,浏览器会校验失败,提示
非官方CA.png针对上面的情况,一般网站会提示我们安装它的证书,使得计算机系统能对浏览器的证书校验成功,比如12306
4.2自签名证书
自签名证书分为两种:自签名私有证书和自签名CA证书,自签名私有证书生成管理简单,而自签名CA证书相对自签名私有证书要更有"体系"标准,是创建者模仿PKI体系搭建的一套自有证书管理系统。由此明显可见两者差异对比
1. 自签名私有证书:无法证书吊销,一旦被黑客获取私钥,那黑客有可能伪装成信任的客户端与服务器通信
2. 自签名CA证书:可以吊销、管理证书,简易版pki,可以创建多个多级的证书。自签名CA证书的Issuer和Subject是一样的
自签名证书.png
5 Android 证书校验
对于App客户端的SSL验证与浏览器的SSL验证通信有相同点,也有不同点
1. 相同点:都需要TSL握手校验
2. 不同点:浏览器只需要保证服务器提供的证书正确,而APP还需要验证证书来源服务器是否是值得信任需要的。
任何人都可以生成他们自己的证书和私钥,客户端在和服务端进行一次通信握手时,服务器会将证书发给客户端,而客户端拿到公钥对证书验证,这个过程只能证明服务器拥有与证书公钥匹配的私钥,不能验证服务器就是我们可信任需要通信的服务器,所以客户端需要也有一套证书集合,如果服务器下发的证书在客户端证书集合内可以找到,那就可以证明服务器是可信任的服务器
5.1客户端如何拥有可信任证书集合
简单上讲让客户端添加可信任的证书即可,但一旦时间长了,服务器升级了更强的密钥(密钥轮换)那证书的公钥就被替换为新的公钥,客户端随之验证失败。如果要解决这个问题那客户端必须要与服务器同步更新密钥。但如果服务器是一个不可控制的第三方网络服务器呢?
庆幸的是Android系统提供了一份顶级的知名CA列表,在Android4.2开始,Android每个版本就更新100多个CA,CA具有一个证书和一个私钥,CA可用私钥签名服务器证书,服务器将证书下发到客户端,客户端即可通过服务器证书进行验证该服务器是否是客户端本身证书集合内的CA颁发的证书。
如果CA为众多的服务器都进行了证书签名,那问题来了,如果这些签名的证书都与客户端通信,那如何确保这些证书是客户端想要的呢?域名校验!
openssl 工具的 s_client 命令将查看 Wikipedia 的服务器证书信息。它指定端口 443,因为这是 HTTPS 的默认端口。此命令将 openssl s_client 的输出发送到 openssl x509,后者将根据 X.509 标准设置证书相关信息的格式。具体而言,此命令会要求相关主题,主题包含服务器名称信息和可识别 CA 的颁发机构。
$ openssl s_client -connect wikipedia.org:443 | openssl x509 -noout -subject -issuer
subject=/serialNumber=sOrr2rKpMVP70Z6E9BT5reY008SJEdYv/C=US/O=*.wikipedia.org/OU=GT03314600/OU=See www.rapidssl.com/resources/cps (c)11/OU=Domain Control Validated RapidSSL(R)/CN=*.wikipedia.org
issuer= /C=US/O=GeoTrust, Inc./CN=RapidSSL CA
通过X509标准证书相关信息我们可以看到证书是由 RapidSSL CA 为与 *.wikipedia.org 匹配的服务器颁发的
5.2 证书验证
-
服务器证书是知名CA版发的证书(客户端系统CA列表也有同CA),那直接就可用简单代码进行发起请求
URL url = new URL("https://wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);
具体的证书校验客户端系统可完全帮你处理,不过这种方式只对知名AC认证的证书有效,有明显的缺陷:
1. 由Android系统校验服务端数字证书的合法性,用可信CA签发数字证书的网站才可以正常访问,私有CA签发数字证书的网站无法访问。
2. 不能抵御在用户设备上安装证书(将中间人服务器的证书放到设备的信任列表中)进行中间人攻击,做此类攻击的一般是为了分析应用和服务器的交互协议,找应用和服务器的其他漏洞。
3. 如果网站没有启用SSL site wide(use HTTPS only)或HSTS(HTTP Strict Transport Security)则无法抵御SSL Strip(HTTPS降级为HTTP)攻击,局域网攻击,如针对免费WiFi。
-
如果服务器证书不是知名CA颁发的证书呢? 如果是自签名证书呢?或者服务器配置缺少中间的CA?
这种情况需要重写校验证书链TrustManager中的方法了(okHttp为例)
没有校验的重写.png上面的重写写法有两个问题
- 没真正实现TrustManger的checkServerTrusted(),需要实现方法校验服务器证书
- 未对服务器证书域名进行强校验--真正实现HostnameVerifier的verify()方法(HttpsURLConnection为例)
还有另外一种写法--证书锁定,直接用预埋的证书来生成TrustManger
预埋证书.png这种证书锁定预埋证书的方式好处就是利用系统实现证书的验证,相对而言其缺点为:无法做到密钥轮换的实时性,在证书即将过期时需要提前一段时间进行更新客户端的预埋证书
到此对于Https的安全校验理解已经有了一个初步的体系架构结果,针对其中的每一个细节点都可扩展到系统性的知识体系,需要后续继续探索。