网上已经有很多关于 TCP/IP 协议等内容,比如阮一峰先生的这篇文章就非常的经典。
简单说起,网络模型一般有两种,TCP/IP 模型和 OSI 模型。前者 5 层,后者 7 层。
从最底层开始说起
协议
每一层都是为了完成一种功能。为了实现这些功能,就需要大家都遵守共同的规则,就叫做”协议”(protocol)。
实体层
就是网线,无线,传输 0 和 1
数据链路层
常用的以太网协议。以太网协议规定,每一组 0 和 1 构成一个数据包,叫做 Frame。Frame 包括 Head 和 Data。下面是用 WireShark 抓到的一个 TCP 三次握手的第一次握手。可以看到,Head 部分主要包括源网卡(本机无线网卡 MAC),目标网卡(无线路由器的 MAC),数据类型。
网络层
可以发现,仅仅把数据传到路由器还不够,还需要路由器把数据转发到目标服务器。如果都在一个局域网,就不会有这个问题。这一层的数据同样有 Head 和 Data。两者组合成为数据链路层的 Data 部分。下图是网络层的 Head 部分,主要是源 IP 和目标 IP。
传输层
有了 IP 还不行,我不知道是哪个程序发送和接收数据。这个时候就需要端口号了。常见的 TCP,UDP 协议就在这一层。比如下面就是 TCP 第一次握手发送的 SYN(0),第二次收到 SYN(0),ACK(1),第三次发送 ACK(1)。这里还可以看到源端口和目标服务器端口。
此外,Socket 也在这一层,是对 TCP/UDP 的抽象封装。比如,在 MySQL 支持的连接方式里面,就有 Socket 和 TCP/IP 两种方式。一般mysql -h 127.0.0.1
就是用的 TCP 连接方式,而直接用mysql
就会去寻找/tmp/mysql.sock 这个套接字,然后试图通过这个套接字与 MySQL 服务器通信。这个文件 0 字节,缺和 MySQL 的端口绑定在一起,进行的通信。
Socket 分为 STREAM(TCP)和 DATAGRAM(UDP)。
TCP 是有状态的连接,三次握手以后就可以保持连接,然后传输数据了。 UDP 是无状态连接,不可靠,但是不用握爪,在实时性上比 TCP 高。
应用层
常见的 HTTP,FTP, SMTP 都在这一层。
面试的时候,常问 HTTP 这些东西,对于非计算机专业的童鞋来说,那个恨啊!
HTTP 是基于 TCP 的无状态连接,所以引入了 Cookie 来实现 session。 HTTP 的 Header 可以设置 Keep-Alive 来保持连接,避免重新三次握手。 GET 和 POST 都是 HTTP 中的两种 METHOD,如果单纯从 TCP 来看,GET 也可以像 POST 一样传 Body,但是服务器那边可能就不认了而已。
请求过程
下图一个完成的 HTTPS 请求过程,包括 DNS 解析,TCP,SSL,服务器处理。深入架构原理与实践
SSL/TLS
网景公司创建了 SSL 1.0, 2.0 和 3.0,随后被 ISO 给接管,随后就出现了 TLS 1.0(SSL 3.1), 1.1(SSL 3.2)和 1.2(SSL 3.3)。
TLS 是介于应用层和传输层之间。详细的握手过程可以参看这里。第一次 TLS 握手需要 2 RTT,加上 TCP 握手 1 RTT 和传输数据 1 RTT,就是 4 个 RTT。
TLS 1.3
TLS 1.3 是 TLS 1.2 的进化版本,移除了一些陈旧的加密算法,简化了加密协商过程,将上面的 2 RTT 降为 1 RTT,可以有效地降低延迟。
HTTPS
严格来说,是 HTTP over TLS。HTTP 是明文的,基于 TLS 进行了加密而已。加密是针对整个 HTTP request 和 response,所以连 Header 都是被加密的。
解决信息传递的安全性
加密就涉及到密钥,由于对称加密的效率高,一般都用对称加密和解密。主要的问题就是密钥的传输安全问题。密钥的传输就不能够再用对称加密了,那不就是无线套娃了,这里就必须要用非对称加密。非对称加密有公钥和私钥,公钥加密的东西只能私钥解,私钥加密的东西只能够公钥解。那又要怎么传递这个公钥,生成传输数据的密钥呢?
HTTPS 的过程
HTTPS 的过程分为证书验证阶段和数据传输阶段,下面的前两步是明文传输,后面才是加密传输。
- 浏览器向服务器发送 client_random,TLS 的版本和浏览器支持的加密方法。
- 服务器向浏览器返回 server_random, 确认好双方都支持的加密算法以及数字证书(证书附带公钥)
- 浏览器向 CA 验证证书,如果通过,则通过协商好的算法生成 premaster secret,并使用数字证书中的公钥进行加密,发送给服务器。
- 服务器用自己的私钥,解密获取 premaster secret。
- 双方根据前面 3 个随机数,生成密钥。此后数据都用该密钥加密传输。
在上面的步骤中,如果我拦截到 1 和 2 两步,能够生成 premaster secret 么?不行。因为它是一个随机数,即你没法保证你生成的随机数和浏览器生成的是一致的,进而没法获取到密钥。
中间人攻击
常见的一些抓包工具 Fiddle, Charles 都可以算是一种中间人,通过拦截浏览器和服务器请求,解密,再用自己的密钥加密发送给双方。但他们有一个共同点,就是需要在浏览器安装自己的证书。此后就是伪装成客户端和服务器,转发消息而已。
Stunnel
stunnel 是一个开源跨平台进行通信加密的软件。它可以对原生不支持加密通信的服务(如 FTP, Telnet 等)在上层提供加密功能,而无须修改这些服务的代码。
stunnel 分为 client 和 server 两种不同的角色,二者之间的通信使用 X509 证书进行加密。如果监听网络,可以看到协议是 TLS 协议。过程和 HTTPS 相似。
SS
有趣的东西。本来 HTTP over TLS 很不错的,不过有一个致命伤就是 SNI。在 TCP 握手之后的第一个 Client Hello request 里面,就有 SNI,里面清晰地标注了 HTTPS 代理服务器的域名。虽然说没法探测到里面的内容,但是大量的流量走向这个服务器,就会引起注意。据我经历,特殊时期,依旧被封。后面可能会缓过来,不过也有很大的可能性就被迫跑路了。
有没有可能一开始就约定好加密协议,避开 TLS 第一次握手的情况,还要保持加密呢?SS 出现了。SS 是基于 Socks 的加密,约定好加密方式和混淆,整个网络传输就是 TCP 层,连接快(国内服务器嘛,ping 值都不错)。数据传输到 SS 服务器,再解密,然后转发出去。传输过程中没有 TLS 的握手过程,直接是加密传输。6
这里有一点就是,依旧是大量的加密数据在传输,墙的技术也在提升(通过捕获、重放等主动侦测来判断是否是代理服务器),也不知道这个技术能够撑到多久。所以暂时一年一年地续费。
科学上网
这里介绍了科学上网的历史,自己经历了里面描述的所有过程。从最开始的 DNS 投毒,IP 封锁,到后来的针对每个 HTTP request 的域名封锁,以及西厢计划,GoAgent,中间用到的 VPN,HTTPS Proxy 和现在用的 SS。
用 Clash 的时候会有一个延迟测试,因为 SS 的服务器基本都是在国内,然后再转发到国外的服务器,所以延迟都很少,但实际网速还是要看 ISP 以及机场的情况。HTTPS Proxy 的延迟可能比较差,因为服务器在国外。自己测试过程中发现,HTTPS PROXY 的速度比 SS 的快,虽然延迟较高。