HTTPS

我们使用 HTTP 传输的内容很容易被中间人窃取、伪造和繁改,通常我们把这种攻击方式称为中间人攻击

什么是 HTTPS

“明文”和“不安全”仅凭 HTTP 自身是无力解决的,需要引入新的 HTTPS 协议,从“HTTP over HTTP ”变成了“ HTTP over SSL/TLS”,让 HTTP 运行在了安全的 SSL/TLS 协议上, 收发报文不再使用 Socket API,而是调用专门的安全接口。

通常我们认为,如果通信过程具备了四个特性,就可以认为是“安全”的,这四个特性是:机密性完整性身份认证不可否认

HTTPS 和 HTTP 有什么区别

  1. HTTPSTCP/IP 的基础上,增加了一层 SLL/TCL 进行安全验证,使报文能够加密传输
  2. HTTP 建立简单,只需要经过三次握手即可进行报文传输,HTTPS 在之后还需要进行 SSL/TLS 握手
  3. HTTP 的端口号是 80HTTPS 则是443
  4. HTTPS 需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

SLL/TLS 又是如何进行加密的呢

加密是针对安全的 4 个特性进行的逐层加密。

机密性

实现机密性最常用的手段就是加密,就是把消息用某种方式转化成乱码。
明文 通过 加密算法 密文
使用 秘钥 还原 明文 的过程叫 解密

按照秘钥的使用方式,可以分成两大类:对称加密和非对称机密;

对称加密

加密和解密使用的都是同一个秘钥。只要保证了秘钥的安全,整个通信过程就可以说具有机密性了
目前常用的对称加密算法只有 AESChaCha20

加密分组模式

对称算法还有一个“分组模式”的概念,它可以让算法用固定长度的密钥加密任意长度的明文,把小秘密 (即密钥)转化为大秘密(即密文)。

最新的分组模式被称为 AEAD,在加密的同时增加了认证的功能,常用的是GCMCCMPoly1305
把上面这些组合起来,就可以得到 TLS 密码套件中定义的对称加密算法。
举个栗子,AES128-GCM,意思是密钥长度为 128 位的 AES 算法,使用的分组模式是 GCM;ChaCha20-Poly1305 的意思是 ChaCha20 算法,使用的分组模式是 Poly1305。

非对称加密

在讲对称加密的时候也提到了,需要保证秘钥的安全。那么我们应该如何交换这个秘钥?

非对称加密,它有两个秘钥,公钥私钥 ,公钥可以公开给任何人使用,而私钥必须严格保密。
非对称加密可以解决“密钥交换”的问题。网站秘密保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,所以就无法破解密文.

非对称加密算法的设计要比对称算法难得多,在 TLS 里只有很少的几种,比如 DHDSARSAECC 等。

  • RSA:它的安全性基于“ 整数分解 ”的数学难题,使用两个超大素数的乘积作为生成密钥的材料,
  • ECC:基于“ 椭圆曲线离散对数 ”的数学难题,使用特定的曲线方程和基点生成公钥和私钥,子算法 ECDHE 用于密钥交换,ECDSA 用于数字签名

比起 RSA,ECC 在安全强度和性能上都有明显的优势

混合加密

非对称加密虽然实现了机密性,但因为基于数学难题,运算速度很慢,抛弃了速度,所以在 TLS 中采用了混合加密的方式。

混合加密方式:用随机数产生对称算法使用的“会话密钥 ”(session key),再用公钥加密。因为会话密钥很短,通常只有 16 字节或 32 字节,所以慢一点也无所谓。然后对方拿到 “会话密钥 ” 再用私钥解密,这就完成了对称秘钥交换。

完整性

摘要算法

摘要算法近似地理解成一种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且 独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”,是一种单向的加密算法。

我们日常工作常用的MD5SHA-1就是摘要算法

目前 TLS 推荐使用的是 SHA-1 的后继者:SHA-2。

完整性

摘要算法保证数字摘要原文是完全等价的。所以,我们只要在原文后附上它的摘要,就能够保证数据的完整性。
如果黑客在中间哪怕改动了一个标点符号,摘要也会完全不同,网站计算比对就会发现消息被窜改,是不可信的。

但是,真正的完整性必须要建立在机密性之上,在混合加密系统里用会话密钥加密消息摘要

数字签名

数字签名是为了解决通信两端的信任问题。
它通过将非对称加密里的“私钥 ”,使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现“身份认证”和“不可否认”。

签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后, 再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的。

数字证书和 CA

CA (Certificate Authority,证书认证机构),具有极高的可信度,由它来给各个公钥签名,用自身的信誉来保证公钥无法伪造, 是可信的。

CA 对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号用途颁发者有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成“数字证书”(Certificate)。

小一点的 CA 可以让大 CA 签名认证,但链条的最后,也就是 Root CA ,就只能自己证明 自己了,这个就叫“自签名证书 ”(Self-Signed Certificate)或者“根证书 ”(Root Certificate)。你必须相信,否则整个证书信任链就走不下去了。

总结为以下三点:

  1. 申请数字证书是不需要提供私钥的,要确保私钥永远只能由服务器掌握;
  2. 数字证书最核心的是 CA 使用它的私钥生成的数字签名;
  3. 内置 CA 对应的证书称为根证书,根证书是最权威的机构,它们自己为自己签名,我们把这称为自签名证书。

证书体系的弱点

如果 CA 失误或者被欺骗,签发了错误的证书,虽然证书是真的,可它代表的网站却是假的。
还有一种更危险的情况,CA 被黑客攻陷,或者 CA 有恶意,因为它(即根证书)是信任的源头,整个信任链里的所有证书也就都不可信了。

密码套件

TLS 的密码套件命名非常规范,格式很固定。基本的形式是“密钥交换算法+签名算法+对称加密算法+分组模式 +摘要算法

举个栗子:server suite : ECDHE-RSA-AES256-GCM-SHA384
server suite 意思是:“握手时使用 ECDHE 算法进行密钥交换,用 RSA 签名和身份认证,握手后的通信使用 AES 对称算法,密钥长度 256 位,分组模式是 GCM,摘要算法 SHA384 用于消息认证和产生随机数。

连接过程解析

TSL1.2

  1. TCP3 次握手
  2. Client Hello” 里面有:客户端的 版本号支持的密码套件随机数(Client Random)
  3. Server Hello” ,对版本号,选择一个密码套件,返回一个 随机数(Server Random)
  4. Server Certificate” 把证书也发给了客户端。
  5. Server Key Exchange” ,发送 公钥(Server Params)私钥签名认证
  6. Server Hello Done ” 服务器表示信息发完了

这样第一个消息往返就结束了(两个 TCP 包),结果是客户端和服务器通过明文共享了三个信息:Client RandomServer RandomServer Params

  1. Client Key Exchange” 发送 公钥(Client Params)
  • Change Cipher Spec

客户端和服务器将 公钥(Server Params)公钥(Client Params)使用 ECDHE 算法一阵算,算出一个新的随机数 “Pre-Master

再使用Client RandomServer RandomPre-Master生成用于加密会话的主密钥“Master Secret

  1. Client “Change Cipher Spec”,计算出主秘钥
  2. Client “**Finished **” 把之前所有发送的数据做个摘要,再加密一下,等待服务器验证
  3. Server “Change Cipher Spec”,计算出主秘钥
  4. Server “**Finished **” 双方都验证加密解密 OK,握手正式结束

TSL1.3

因为密码套件大幅度简化,也就没有必要再像以前那样走复杂的协商流程了。TLS1.3 压缩了以前 的“Hello”协商过程,删除了“Key Exchange”消息,把握手时间减少到了“1-RTT”,效率提高了一倍。

  • 首先浏览器向服务端发送 Client -random可使用的对称密码套件和非对称加密套件
  • 服务器端保存 Client-random,并返回 server-random选择的密码套件公钥(这里加上 CA 发送的是数字证书)、密钥交换算法的公钥(Server Params)
  • 浏览器拿到数据后,也生成一个Client Param ,对 Client -randomserver-random ,Server Params,Client Params使用 ECDHE 算法 生成 Pre-master,并使用公钥加密发送给服务器

pre-master 是经过公钥加密之后传输的,所以黑客无法获取到 pre-master,这样黑客就无法生成密钥,也就保证了黑客无法破解传输过程中的数据了

  • 服务器收到后,使用私钥解密并验证合法性,至此,两边就都可以通过 cilent-randomserver-randomPre-master 三个共同随机数生成对称秘钥(Master Secret)进行加密传输了
master_secret = PRF(
  pre_master_secret,
  "master	secret",
  ClientHello.random + ServerHello.random
);

这里的“PRF”就是伪随机数函数,它基于密码套件里的最后一个参数,

双向认证

上面说的是“单向认证” 握手过程,只认证了服务器的身份,而没有认证客户端的身份。这是因为通常单向认证通过后已经建立了安全通信,用账号、密码等简单的手段就能够确认用户的真实身份。

但为了防止账号、密码被盗,有的时候(比如网上银行)还会使用 U 盾给用户颁发客户端证书,实现“ 双向认证”,这样会更加安全。
双向认证的流程也没有太多变化,只是在“Server Hello Done ”之后,“Client Key Exchange Client”之前,客户端要发送“ Client Certificate”消息,服务器收到后也把证书链走一遍,验证客户端的身份。

常见问题

客户端如何验证证书的合法性

操作系统和浏览器等在安装时候就预装了 CA(证书机构)列表,服务商在使用 https 前,会向 CA 请求颁发签名,在建立 https 连接的时候,浏览器会查看证书签名颁发机构是否在 CA 列表,如果是表示可以信任。

具体是,服务端生成密钥对(k1,k2), 将实体信息以及 k1 发送给 CA,获取证书,CA 对签名内容 hash 生成消息摘要,CA 用自己私钥 k2-CA 对消息摘要加密,生成签名,浏览器在校验时,获取到相应 CA 的公钥(预装),对签名解密,获取消息摘要,同时通过相同的 hash 函数对证书消息 hash 生成摘要,两者对比,如果相同则信任

为什么要证书

客户端和服务端会使用双方的公钥生成一个随机数Pre-Master,然后再使用三个随机数生成传输使用的主密钥,如果中间人冒充,对两边的公钥进行伪造,则后面的加密都将无效,而 CA 就用于保证,你获得的公钥确实是你要访问的可靠网站的公钥,而不是别人冒充的。

HTTP 传输消息都是明文的,黑客完全可以作为中间人劫持消息,再利用 ECDHE 算法,这样不就能破解密钥了吗?

ECDHE 算法利用了椭圆曲线和离散对数等思想,按照当下的计算机算力,很难在短时间进行破解。且每次握手时生成的都是一对临时的公钥和私钥,这样就保证每次的密钥对也不同。

即使大费力气破解了一次的密钥,之前的历史消息也不会受到影响,保证了前向安全。

为什么要是三个随机数

TLS 的设计者不信任客户端或服务器伪随机数的可靠性,为了保证真正 的“完全随机”“不可预测”,把三个不可靠的随机数混合起来,那么“随机”的程度就非常高了,足够让 黑客难#

为什么使用 HTTPS 了,公司还能知道访问了哪些网站

这是因为 HTTPS 采用的 TLS 连接,TLS 虽然会建立安全的信息通信,但是在握手初期,信息都是明文的。我们在学习 TLS 的时候看到只传输了版本号支持的密码套件随机数(Client Random)。但其实,还有 SNI等一些服务器信息

那么,握手过程为什么要包含SNI呢?

这是因为,当多个网站托管在一台服务器上并共享一个IP地址,且每个网站都有自己的SSL证书时,那就没法通过IP地址判断客户端是想和哪个网站建立TLS连接,此时就需要域名信息辅助判断。

那么应该如何避免呢?

TLS 1. 3 有一个扩展Encrypted ClientHello,用于加密Client Hello消息中的SNI等信息。

开启ECH需要同时满足:

  • 服务器支持TLSECH扩展
  • 客户端支持ECH

还有一种是安全 DNS


本地 CA 证书

参考资料