### 摘要和非对称加密
在了解的安全协议之前,需要先讲两个前置概念,也是后续理解的关键。
**摘要:** 摘要算法是对数据的有损压缩,是单向不可逆的,就是一种哈希运算结果。可以用来做数据比较,当两份数据的摘要结果是一致的,说明两份数据也是一致的。常用的摘要算法:MD5、SHA-1等。
**非对称加密:**
- 非对称加密,则有公钥、私钥之分,公钥可以公开,且**加密解密只能是单向的**,公钥加密私钥解密,或私钥加密公钥解密。
- 但由于公钥是公开的,所以私钥加密相当于所有人都可以解密,但这并不意味着私钥加密没有意义。当一个信息可以由公钥成功解密,就证明此消息必然是私钥持有者发出,这就**能起到验证信息来源的作用,像一个签名**。所以一般不叫私钥加密公钥解密,而是私钥签名公钥解签。
- 非对称加密需要复杂的运算,所以一般不会去加密数据本身,而是加密数据的摘要,然后接收方解密摘要后,再对收到数据进行校验,从而确定接受信息的可靠性。
- 常用的是 RSA 算法,它的密钥有 256/512/1024/2048/4096 等不同的长度。长度越长,密码强度越大,当然计算速度也越慢。
- **注:非对称加密是 HTTPS 实现安全传输的关键!**
### 如何设计一个安全通信方案?
下面将会一步一步设计一个安全的通讯协议,每一个阶段会列出解决和遗留的问题。
1. 明文通讯
- 安全问题
1. 双方对称加密通讯,双方线下存储密钥
- 信息可以加密
- 随着通讯对象增加,需要存储的密钥会越来越多
- 每增加一个对象,都必须线下去交换一次密钥,非常麻烦
1. 非对称加密通讯,明文将公钥发出,双方交换公钥
- 公钥可以明文发送,不需要线下分配密钥,也不需要事先存好密钥
- 每次通讯都用非对称加密,计算量大
- 公钥对所有人开放,即意味着无法确定信息的准确来源,是谁发过来的
- 公钥交换过程是明文,可能会被中间人劫持修改(中间人在传输过程中修改成自己的公钥,即可监听对话)
1. 非对称加密传送密钥,然后再通过对称加密通讯。即生成一个密钥 A,通过公钥加密传输给对方,并告诉对方之后的通话要经过密钥 A 来加密。
- 解决非对称加密计算量大问题
- 仍无法确认信息来源
- 中间人劫持公钥
1. 到这里,如果不解决中间人劫持的问题,就无法进行下去了。所以我们需要引入一个可靠的第三者,我们称之为**授信机构**,机构生成一对非对称密钥,每个需要通讯的人都去此机构领取公钥,并且机构会对申请人的个人信息进行认证和签名(私钥加密)。此后,所有人通讯前,都用机构公钥去解密对方的机构签名,这样就能确认对方是谁了。所以此机构相当于是一个互联网的身份登记机构。
- 可以确认信息来源,同时杜绝了中间人劫持
由于存在授信机构,只需要申请一次公钥(证书),且只需要存储一个公钥,即可跟所有人进行加密通讯。而这个授信机构也就是现在的 CA机构(证书授权中心),机构签名和公钥则构成数字证书,每个浏览器都会内置 CA机构 的根证书。
下面会讲述数字证书和安全协议的更多细节。
### 数字证书
CA 机构(证书授权中心)会生成一个根证书(带有公钥)和私钥,根证书会内置在所有浏览器里,私钥则用于服务器证书的签名。所以只有经过机构认证的服务器,才能进行加密通信。
CA 机构向有资质的服务器发放服务器证书,不同安全等级的证书需要不同的申请资料,如申请电子商务服务器证书需要营业证明。
下图是证书的内容:(下面颁发者的签名只是个比喻,实际应该是一串加密字符)

一个受根证书信任的证书 A,可以对另一个新建的证书 B 进行签名,这样根证书也会信任证书 B,这是一个证书信任链条。所以**并非只有根证书才能给其他证书签名。**


当客户端收到服务端的证书,会通过证书的**发布机构(Issuer)**递归向上反查到其根证书,从而保证证书信任链的有效。
### SSL 和 TLS 安全协议
两者都是加密层的协议,**TLS 是 SSL 的更新版本**,修复了一些安全漏洞。**因为两者很相似,所以下面以 SSL 为代表讲解安全层是如何建立的。**

### 建立 SSL 连接
1. 客户端发送支持的安全协议、加密方法、随机数a(客户端生成)等;
1. 服务器返回确认的安全协议、加密方法,以及随机数b(服务端生成)和证书;
1. 客户端验证证书,首先查看证书的颁发机构、期限以及域名等,保证了证书本身信息合法后,通过根证书的公钥验明证书上的签名。验签后,取出证书公钥,对此次发送的信息进行加密。这次会发送给服务端随机数c(客户端生成),并通知服务端之后的通信将用密钥加密;
1. 服务端最后一次返回,通知客户端已知后续内容要加密,并且将之前发送内容生成hash值一并返回给客户端,以供客户端校验;
1. 通过前面几次握手,共产生随机数a、b、c,且同时存在于两端,两端用这三个随机数生成密钥,通过约定好的加密算法加密之后通讯的内容;

- 注:通过两端产生的三个随机数,能更好地保证密钥的随机性,其中 a、b 随机数是明文传输,只有 c 是通过服务器公钥加密传输的;
### 如何确定明文证书不会被劫持?
在证书生成的时候,除了有基本信息外,还有颁发机构的私钥签名,这个签名是通过对整个证书的内容(包括服务器公钥)摘要加密生成的。
所以如果有中间人想要调包证书,那浏览器会找不到解签的公钥而判定此证书是非法证书。
如果想把证书公钥换成中间人自己的,也不行,因为客户端也会对证书内容进行摘要,然后再跟证书解签出来的摘要进行对比,这样就能知道证书内容是否被修改过。
### 每次会话都需要握手吗?
SSL 的多次握手需要一定时间,所以当连接断开一段时间内,双端都会保留一个 **Session Id** 用于快速重新握手。当重连时,客户端依然进行第一次握手,但会带上之前连接保留下来的 Session Id;服务端在上此连接时,将 Session Id 作为 key,密钥作为 value 存储起来,拿到客户端发来的 Session Id 就可以验证是否存在过,存在则告知客户端恢复连接。
**但 Session Id 存在两个问题**,一是服务端存储大量的 Session Id 和通信密钥,内存占用高;二是如果服务器是集群,则需要一个共享数据库去存储 Session Id,增加读写性能压力。
为了解决这两个问题,后来协议新增了一个 **Session Ticket**。顾名思义,它是服务端给客户端发送的一个票据,通过这个票据可以恢复会话,不再需要存储于客户端。具体操作是,当完成完整握手后,**服务端会将此次的通讯密钥加密成 Ticket 发送给客户端**(Ticket 只有服务器能解密),并且还需要告知客户端 Ticket 的时效,到时必须删除。当客户端之后重连时,将 Ticket 带给服务端,服务端解密出上次的通讯密钥,即可恢复加密通信。
### https 代理
在写这篇文章的同时,我实现了一个简单的代理抓包工具,感兴趣的可以看下 https://github.com/Mess663/v-proxy
**参考:**
[](https://imququ.com/post/web-proxy.html)<https://imququ.com/post/web-proxy.html>
[](https://awesome-programming-books.github.io/http/HTTP%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97.pdf)[https://awesome-programming-books.github.io/http/HTTP权威指南.pdf](https://awesome-programming-books.github.io/http/HTTP%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97.pdf)
[](https://github.com/anzhihe/Free-Web-Books/blob/master/book/HTTPS%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97.pdf)[https://github.com/anzhihe/Free-Web-Books/blob/master/book/HTTPS权威指南.pdf](https://github.com/anzhihe/Free-Web-Books/blob/master/book/HTTPS%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97.pdf) h[ttps://www.lyyyuna.com/2018/03/16/http-proxy-https/](https://www.lyyyuna.com/2018/03/16/http-proxy-https/) [](https://www.ruanyifeng.com/blog/2014/02/ssl_tls.html)<https://www.ruanyifeng.com/blog/2014/02/ssl_tls.html> [](https://www.bookstack.cn/read/https-mitm-proxy-handbook/doc-Chapter3.md)<https://www.bookstack.cn/read/https-mitm-proxy-handbook/doc-Chapter3.md> [](https://segmentfault.com/a/1190000024523772)<https://segmentfault.com/a/1190000024523772>
摘要和非对称加密
在了解的安全协议之前,需要先讲两个前置概念,也是后续理解的关键。
摘要: 摘要算法是对数据的有损压缩,是单向不可逆的,就是一种哈希运算结果。可以用来做数据比较,当两份数据的摘要结果是一致的,说明两份数据也是一致的。常用的摘要算法:MD5、SHA-1等。
非对称加密:
- 非对称加密,则有公钥、私钥之分,公钥可以公开,且加密解密只能是单向的,公钥加密私钥解密,或私钥加密公钥解密。
- 但由于公钥是公开的,所以私钥加密相当于所有人都可以解密,但这并不意味着私钥加密没有意义。当一个信息可以由公钥成功解密,就证明此消息必然是私钥持有者发出,这就能起到验证信息来源的作用,像一个签名。所以一般不叫私钥加密公钥解密,而是私钥签名公钥解签。
- 非对称加密需要复杂的运算,所以一般不会去加密数据本身,而是加密数据的摘要,然后接收方解密摘要后,再对收到数据进行校验,从而确定接受信息的可靠性。
- 常用的是 RSA 算法,它的密钥有 256/512/1024/2048/4096 等不同的长度。长度越长,密码强度越大,当然计算速度也越慢。
- 注:非对称加密是 HTTPS 实现安全传输的关键!
如何设计一个安全通信方案?
下面将会一步一步设计一个安全的通讯协议,每一个阶段会列出解决和遗留的问题。
明文通讯
双方对称加密通讯,双方线下存储密钥
- 信息可以加密
- 随着通讯对象增加,需要存储的密钥会越来越多
- 每增加一个对象,都必须线下去交换一次密钥,非常麻烦
非对称加密通讯,明文将公钥发出,双方交换公钥
- 公钥可以明文发送,不需要线下分配密钥,也不需要事先存好密钥
- 每次通讯都用非对称加密,计算量大
- 公钥对所有人开放,即意味着无法确定信息的准确来源,是谁发过来的
- 公钥交换过程是明文,可能会被中间人劫持修改(中间人在传输过程中修改成自己的公钥,即可监听对话)
非对称加密传送密钥,然后再通过对称加密通讯。即生成一个密钥 A,通过公钥加密传输给对方,并告诉对方之后的通话要经过密钥 A 来加密。
- 解决非对称加密计算量大问题
- 仍无法确认信息来源
- 中间人劫持公钥
到这里,如果不解决中间人劫持的问题,就无法进行下去了。所以我们需要引入一个可靠的第三者,我们称之为授信机构,机构生成一对非对称密钥,每个需要通讯的人都去此机构领取公钥,并且机构会对申请人的个人信息进行认证和签名(私钥加密)。此后,所有人通讯前,都用机构公钥去解密对方的机构签名,这样就能确认对方是谁了。所以此机构相当于是一个互联网的身份登记机构。
由于存在授信机构,只需要申请一次公钥(证书),且只需要存储一个公钥,即可跟所有人进行加密通讯。而这个授信机构也就是现在的 CA机构(证书授权中心),机构签名和公钥则构成数字证书,每个浏览器都会内置 CA机构 的根证书。
下面会讲述数字证书和安全协议的更多细节。
数字证书
CA 机构(证书授权中心)会生成一个根证书(带有公钥)和私钥,根证书会内置在所有浏览器里,私钥则用于服务器证书的签名。所以只有经过机构认证的服务器,才能进行加密通信。
CA 机构向有资质的服务器发放服务器证书,不同安全等级的证书需要不同的申请资料,如申请电子商务服务器证书需要营业证明。
下图是证书的内容:(下面颁发者的签名只是个比喻,实际应该是一串加密字符)

一个受根证书信任的证书 A,可以对另一个新建的证书 B 进行签名,这样根证书也会信任证书 B,这是一个证书信任链条。所以并非只有根证书才能给其他证书签名。


当客户端收到服务端的证书,会通过证书的发布机构(Issuer)递归向上反查到其根证书,从而保证证书信任链的有效。
SSL 和 TLS 安全协议
两者都是加密层的协议,TLS 是 SSL 的更新版本,修复了一些安全漏洞。因为两者很相似,所以下面以 SSL 为代表讲解安全层是如何建立的。

建立 SSL 连接
- 客户端发送支持的安全协议、加密方法、随机数a(客户端生成)等;
- 服务器返回确认的安全协议、加密方法,以及随机数b(服务端生成)和证书;
- 客户端验证证书,首先查看证书的颁发机构、期限以及域名等,保证了证书本身信息合法后,通过根证书的公钥验明证书上的签名。验签后,取出证书公钥,对此次发送的信息进行加密。这次会发送给服务端随机数c(客户端生成),并通知服务端之后的通信将用密钥加密;
- 服务端最后一次返回,通知客户端已知后续内容要加密,并且将之前发送内容生成hash值一并返回给客户端,以供客户端校验;
- 通过前面几次握手,共产生随机数a、b、c,且同时存在于两端,两端用这三个随机数生成密钥,通过约定好的加密算法加密之后通讯的内容;

- 注:通过两端产生的三个随机数,能更好地保证密钥的随机性,其中 a、b 随机数是明文传输,只有 c 是通过服务器公钥加密传输的;
如何确定明文证书不会被劫持?
在证书生成的时候,除了有基本信息外,还有颁发机构的私钥签名,这个签名是通过对整个证书的内容(包括服务器公钥)摘要加密生成的。
所以如果有中间人想要调包证书,那浏览器会找不到解签的公钥而判定此证书是非法证书。
如果想把证书公钥换成中间人自己的,也不行,因为客户端也会对证书内容进行摘要,然后再跟证书解签出来的摘要进行对比,这样就能知道证书内容是否被修改过。
每次会话都需要握手吗?
SSL 的多次握手需要一定时间,所以当连接断开一段时间内,双端都会保留一个 Session Id 用于快速重新握手。当重连时,客户端依然进行第一次握手,但会带上之前连接保留下来的 Session Id;服务端在上此连接时,将 Session Id 作为 key,密钥作为 value 存储起来,拿到客户端发来的 Session Id 就可以验证是否存在过,存在则告知客户端恢复连接。
但 Session Id 存在两个问题,一是服务端存储大量的 Session Id 和通信密钥,内存占用高;二是如果服务器是集群,则需要一个共享数据库去存储 Session Id,增加读写性能压力。
为了解决这两个问题,后来协议新增了一个 Session Ticket。顾名思义,它是服务端给客户端发送的一个票据,通过这个票据可以恢复会话,不再需要存储于客户端。具体操作是,当完成完整握手后,服务端会将此次的通讯密钥加密成 Ticket 发送给客户端(Ticket 只有服务器能解密),并且还需要告知客户端 Ticket 的时效,到时必须删除。当客户端之后重连时,将 Ticket 带给服务端,服务端解密出上次的通讯密钥,即可恢复加密通信。
https 代理
在写这篇文章的同时,我实现了一个简单的代理抓包工具,感兴趣的可以看下 https://github.com/Mess663/v-proxy
参考:
https://imququ.com/post/web-proxy.html
https://awesome-programming-books.github.io/http/HTTP权威指南.pdf
https://github.com/anzhihe/Free-Web-Books/blob/master/book/HTTPS权威指南.pdf https://www.lyyyuna.com/2018/03/16/http-proxy-https/ https://www.ruanyifeng.com/blog/2014/02/ssl_tls.html https://www.bookstack.cn/read/https-mitm-proxy-handbook/doc-Chapter3.md https://segmentfault.com/a/1190000024523772