HTTPS
学习时间:2020.06.14
学习章节:透视HTTP协议
一、主要知识点
- 什么是 HTTPS
- 什么是 SSL/TLS
- 什么是加密、摘要算法
- 数字签名与证书
- TLS 连接过程
1. HTTPS
1.1 为什么要有 HTTPS
因为 HTTP 天生 “明文” 的特点,传输过程完全透明,任何人都可以在链路中截获或者修改 请求/响应报文 ,数据不具有可信性。各种应用场景暴露的问题:
- 网络购物、网上银行、证券交易等需要高度信任的应用场景没有得到安全保护。
- 新闻、视频、搜索等网站,容易遭到 “流量劫持” 攻击,在页面嵌入广告,或者分流用户。
- 普通网民的上网记录被截获,黑客可以伪装成银行网站,盗取用户信息,威胁客户人身和财产安全。
1.2 什么是 HTTPS
HTTPS 的协议名为 “https“ 默认端口为 443,其他的 请求-应答模式、报文结构、请求方法、URI、头字段、连接管理等都完全沿用 HTTP,没有其他新的东西。
它为 HTTP 添加了四大安全特性:
- 机密性:对数据保密,只能由可信的人访问。
- 完整性:数据传输过程没有被篡改,完完整整的保持着原状。
- 身份认证:确认对方的真实身份,保证消息只能发送给可信的人。
- 不可否认:不能否认已经发生过的行为。
在 HTTPS 中,它把 HTTP 下层的传输协议由 TCP/IP 换成了 SSL/TLS,由 “HTTP over TCP/IP” 变成了 “HTTP over SSL/TLS”,让 HTTP 运行在安全的 SSL/TLS 协议上。这就是 HTTPS 中的 “S” 的意思。
2. SSL/TLS
SSL(Secure Sockets Layer)安全套接层,它在 1999 年被改名为 TLS(Transport Layer Security)传输层安全。它由 记录协议、握手协议、警告协议、更新密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等技术。
3. 什么是加密
3.1 加密
加密就是把消息用某种方式转换成谁也看不懂的乱码,只有掌握特殊 “钥匙” 的人才能再转换出原始文本。钥匙叫做密钥,加密前的消息叫做明文,加密后的乱码叫密文,使用密钥还原明文的过程叫解密,加密解密的过程叫做加密算法。
由于 HTTPS、TLS 都运行在计算机上,密钥是一长串的数字,但约定俗成的度量单位是位(bit),而不是字节(byte)。比如:密钥长度是 128,就是16字节的二进制串,密钥长度1024,就是128字节的二进制串。
加密可以分为两大类:对称加密和非对称加密。
3.2 对称加密
对称加密:就是指加密和解密时使用的密钥都是同一个,是对称的,只要保证了密钥的安全,那整个通信过程就可以说具有了机密性。
TLS 里有很多的对称加密算法可供选择,比如 RC4、DES、3DES、AES、ChaCha20等,前三种算法被认为是不安全的,通常禁止使用,目前常用的只有AES 和 ChaCha20。
加密分组模式:对称算法还有一个 分组模式 的概念,它可以让算法用固定长度的密钥加密任意长度的明文。最早有ECB、CBC、CFB、OFB几种分组模式,但是都被发现有安全漏洞,所以不怎么用了。现在最新的分组模式被称为AEAD(Authenticated Encryption with Associated Data),加密的同事增加了认证的功能,常用的是 GCM、CCM 和 Poly1305.
上面这些组合起来就得到 TLS 密码套件中定义的对称加密算法。
3.2.1 AES算法原理
3.3 非对称加密
上面的对称加密看起来好像实现了机密性,但是其中一个很大的问题就是如何把密钥安全的传递给对方,术语叫做密钥交换。
对称加密算法中只要持有密钥就可以解密,如果你和网站约定的密钥在传输中被窃取。通信过程就无机密性了。所以出现了非对称加密。
非对称加密有两个密钥,一个叫公钥,一个叫私钥。两个密钥是不同的,公钥可以给任何人使用,而私钥必须严格保密。公钥和私钥都是单向性的,虽然可以用来加密解密,但是公钥加只能私钥解,私钥加只能公钥解。
非对称加密可以用于解决以上 密钥交换 的问题。网站保管私钥,在网上分发公钥。公钥对原文加密,传输加密后的密文给网站,网站使用私钥解密出密文得到原文。黑客没有私钥,所以解不出密文。
非对称加密的算法设计比对称算法难得多,在 TLS 里只有很少几种,比如 DH、DSA、RSA、ECC 等。RSA 的安全性基于 “整数分解” 的数学难题,使用两个超大质数的乘积作为生成密钥的材料。想要从公钥推算出私钥是非常困难的。
素数和质数是没有区别的。质数(又称素数),是指在大于1的自然数中,除了1和它本身外,不能被其他自然数整除(除0以外)的数称之为素数(质数)。
3.3.1 RSA 算法
- 随机选取两个质数p和q
- 计算 n = pq
- 计算 φ(n) = (p-1)(q-1)
- 找一个与φ(n)互质的小奇数e,互质是指两个数的公约数只有1
- 对模φ(n),计算e的乘法逆元d,即找到一个d,使下列等式成立:(e*d) mod φ(n) = 1
- 得到公钥:(e, n),私钥: (d, n)
- 加密过程:c = (m^e) mod n, (c为加密后的密文,m为原文)
- 解密过程:m = (c^d) mod n
示例:
- 随便选两个质数23和61
- 计算 n = 23 * 61 = 1403
- 计算 φ(n) = (23-1) (61-1) = 22 60 = 1320
- 找一个与φ(n)互质的小奇数e,我们选7
- 计算乘法逆元d,我这里算好的是 d =943。对乘法逆元感兴趣的朋友可以网上搜搜怎么算,因为不是本文主题,我就不展开了。
- 得到公钥(7, 1403),私钥(943, 1403)
- 我们用公钥随便加密一个5试试,加密 c = (m^e) mod n = (5^7) % 1403 = 78125 % 1403 = 960
- 私钥解密: m = (c^d) mod n = (960^943) % 1403 = 5,(960^943)这个数字超级大,一般计算器算不出来,JS计算更不行,我是用这个网站算的:https://defuse.ca/big-number-calculator.htm
- 再试试私钥加密:c = (m^d) mod n = (5^943) % 1403 = 283
- 公钥解密: m = (c^e) mod n = (283 ^ 7) % 1403 = 5
3.4 混合加密
非对称加密虽然没有了 “密钥交换” 中存在的问题,但是它们都是因为基于复杂的数学难题,所以运算速度很慢。所以出现了混合加密的方式,也就是两种加密方式之间的取长补短。既能高效加密,又能安全的密钥交换。
这就是现在 TLS 里使用的混合加密方式,在通信刚开始的时候使用非对称加密解决密钥交换的问题。然后随机产品对称算法的会话密钥,再用公钥加密得到密文,对方拿到密文之后使用私钥解密,取出会话密钥,之后就都使用对称加密了。
混合加密解决了对称加密算法的密钥交换问题,也解决了非对称加密算法的性能问题。完美的实现了机密性。
4. 数字签名与证书
通过上面的混合加密,黑客拿不到密钥,无法破解密文,但是可以通过收集足够多的密文,尝试修改、重组后发送给网站。因为没有完整性保证,服务器只能照单全收。然后黑客通过服务器的响应获取线索,最终破解出明文。
还有黑客可以伪造身份发布公钥,如果你拿到假的公钥,混合加密就失效了。你以为是在和真实的网站通信,实际上确实和黑客通信。身份信息也就泄漏了。因为不具备身份认证的特性
所以机密性的基础上还得加上完整性、身份认证等特性、才能实现真正的安全。
4.1 摘要算法
实现完整性的手段主要是摘要算法,它能够把任意长度的数据压缩成固定长度、而且独一无二的摘要字符串,就好像是给这段数据生成一个数字指纹。(摘要算法加密后的数据无法解密,不能从摘要逆推原文)。
摘要算法实际上是把数据从一个 大空间 映射到 小空间。所以就存在冲突(也叫碰撞)的可能性。因为摘要算法对输入具有单向性和雪崩效应,输入微小的不同导致输出的剧烈变化,所以也被 TLS 用来生成伪随机数(PRF,pseudo random function)。
常用的摘要算法有:MD5(Message-Digest 5)、SHA-1(Secure Hash Algorithm 1),它们就是最常用的两个摘要算法,能够生成 16 字节和 20 字节长度的数字摘要。但是这两个算法的安全强度比较低,不够安全,在 TLS 里已经被禁止使用了。目前 TLS 推荐使用的是 SHA-1 的后继者: SHA-2。
4.1.1 那么如何通过摘要算法保证数据的完整性
假设你发送了一条消息,“转账1000元”,再加上 SHA-2 的摘要。两个一起传输给网站,网站拿到之后也计算一下得到消息的摘要。然后比对一下两份摘要是否一致,就能知道消息是否完整可信,有没有被修改。
不过摘要算法不具有机密性,如果明文传输,黑客可以修改消息后把摘要也一起改了。网站还是鉴别不出完整性。
所以,真正的完整性必须要建立在机密性之上,在混合加密系统里用会话秘钥加密消息和摘要,黑客就无法得知明文,也就没办法动手脚了。
4.2 数字签名
加密算法结合摘要算法,我们的通信过程可以说是比较安全了,但这里还有个漏洞,就是通信的两个端点。黑客可以伪装成网站来窃取信息。他也可以伪装成你,向网站发送支付、转账等消息,网站没有办法验证你的身份,钱就被盗走了。
现实生活中,解决身份认证的手段是签名和印章,只要在纸上写下签名或者盖个章,就能够证明这份文件确实是本人而不是其他人发出的。而 TLS 里的非对称加密的 私钥 就像这个印章。使用私钥加上摘要算法,就能够实现 数字签名,同时实现 身份认证 和 不可否认。
数字签名的原理就是把公私钥的用法反过来,之前公钥加密、私钥解密。现在是私钥加密、公钥解密。但是因为非对称加密效率太低,所以私钥只加密原文的摘要,这样子运算量小很多。得到的数字签名也很小,方便保管和传输。
数字签名 和 公钥 一样完全公开,任何人都可以获取,但这个签名只有私钥对应的公钥才能解开,拿到 摘要后,再对比原文验证完整性,就可以像签署文件一样证明消息确实是你发的了。
这两个行为也有专业术语,叫 签名 和 验签
只要你和网站互相交换公钥,就可以用 签名 和 验签 来确认消息的真实性,因为私钥保密,黑客不能伪造签名,就能够保证通信双方的身份。
比如你用自己的私钥签名一个消息,“我是小秦”,网站收到你的公钥之后验签确认身份。然后网站也用它的私钥签名一个消息 “我是网站”,发送给你。你收到以后拿它的公钥验证一下,也没有问题。这样你和网站都知道对方没问题了。时候就可以用混合加密进行安全通信了。
4.3 数字证书与 CA
到现在综合使用对称、非对称加密和摘要算法之后,还存在一个问题,就是 公钥的信任问题,上面说的签名与验签只能保证通信双方的身份没问题。但是却不能知道对方是什么身份(是真实的网站还是黑客呢)。因为谁都可以发布公钥,这里还缺少防止黑客伪造公钥的手段。也就是说怎么判断 公钥就是小秦的或者是网站的呢
CA(Certificate Authority,证书认证机构),它像是网络世界的公安局、公正中心,由它来给各个公钥签名,用自身的信誉来保证公钥无法伪造,是可信的。
CA 对公钥的签名认证也是有格式的,不是简单的把公钥绑定在持有者身份上就完事了,还要包含序列号、用途、颁发者、有效时间等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成 数字证书。
操作系统和浏览器中都内置了各大 CA 的根证书,上网的时候只要服务器发过来它的证书,就可以验证证书是否可信。从而验证里面的公钥也是否是可信的了。
五、TLS 连接过程
5.1 TLS 协议组成
记录协议(Record Protocol):规定了 TLS 收发数据的基本单位:记录(record),它有点像是 TCP 里的 segment,所有的其他自协议都需要通过记录协议发出。但多个记录数据可以再一个 TCP 包里一次性发出,也冰不需要像 TCP 那样返回 ACK。
警报协议(Alert Protocol):的职责是向对方发出警报信息,有点像是 HTTP 协议里的状态 码。比如,protocol_version 就是不支持旧版本,bad_certificate 就是证书有问题,收到 警报后另一方可以选择继续,也可以立即终止连接。
握手协议(Handshake Protocol):是 TLS 里最复杂的子协议,要比 TCP 的 SYN/ACK 复 杂的多,浏览器和服务器会在握手过程中协商 TLS 版本号、随机数、密码套件等信息,然 后交换证书和密钥参数,最终双方协商得到会话密钥,用于后续的混合加密系统。
变更密码规范协议(Change Cipher Spec Protocol):它非常简单,就是一 个“通知”,告诉对方,后续的数据都将使用加密保护。那么反过来,在它之前,数据都是 明文的。
TLS 握手简要过程:
TLS 握手的前几个消息都是明文的,在 Change Copher Spec 之后数据都是密文的。
5.2 详细握手过程
- 在浏览器输入 https 开头的 URI,并且回车之后,浏览器从 URI 里提取出协议名和域名,因为协议名是 https ,所以浏览器就知道了端口号默认是 443,它在用 DNS 解析域名,得到目标的 IP 地址,然后就可以使用三次握手与网站建立 TCP 连接。
- 建立 TCP 连接后,浏览器首先发送一个 Client Hello 的消息,里面有客户端的版本号、支持的密码套件、还有一个随机数。
- 服务器收到 Client Hello 后,会返回一个 Server Hello 的消息,把版本号对一下,也给出一个随机数、从客户端列表里选一个作为本地通信使用的密码套件(比如椭圆曲线加 RSA、AES、SHA384)。
然后服务器为了证明自己的身份,就把证书也发给了客户端(Server Cenrtificate),接下来服务器因为选择了ECDHE 算法,所以它会在证书后发送 Server Key Exchange 消息,里面是 椭圆曲线的公钥(Server Params)用来实现密钥交换算法,再加上自己的私钥签名认证。之后就是 Server Hello Done 的消息,服务器说 我的信息就是这些,打招呼完毕。
- 客户端拿到服务器的证书,需要验证证书是不是真实有效的。验证完之后把证书里携带的(服务器的)公钥拿出来验证签名,就确认了服务器的身份。
客户端按照密码套件的要求,也生成一个 椭圆曲线的公钥(client params),用 Client Key Exchange 消息发给服务器。
客户端和服务器都拥有了密钥交换算法的两个参数 Client Params 和 Server Params,之后通过 ECDHE 算法得到一个新的随机数 “Pre-Master“,这个算法保证了黑客截获之前的参数,也绝对算不出这个随机数。
- 现在客户端和服务端一共拥有三个随机数:Client Radndom、Server Random 和 Pre-Master。用这三个作为原始材料,就可以生成用于加密会话的主密钥,叫 Master Secret。因为黑客拿到不到 Pre-Master 所以得不到主密钥。
- 主密钥有 48 字节,但它也不是最终用于通信的会话密钥,还会拓展出更多的密钥,比如客户端发送用的会话密钥(client_write_key),服务器发送用的会话密钥(serve_write_key)等等,避免只用一个密钥带来的安全隐患。
- 有了主密钥和会话密钥,握手就快结束了。客户端发一个 Change Cipher Spec ,然后再发一个 Finished 消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证。
- 服务器也同样的炒作,发 Change Cipher Spec 和 Finished 消息,双方都验证加密解密ok。握手就结束了,后面就开始收发被加密的 HTTP 请求和响应。