计算机网络

前言

本文主要是记录下计算机网络的基本知识点,包括因特网协议栈、应用层、传输层以及 Https 的相关知识。

因特网协议栈

因特网协议栈由以下5个层次组成,按照自顶向下分别为:

  1. 应用层,HTTP、SMTP、FTP,报文。
  2. 运输层,TCP、UDP,报文段,端到端。
  3. 网络层,IP,数据报,主机到主机。
  4. 链路层,帧。
  5. 物理层。

发送方:应用层构建报文,传递给运输层(通过 Socket),运输层添加一些首部信息(差错检测位等)组成报文段,传递给网络层,网络层添加一些首部信息(源和目的地址等)组成数据报,传递给链路层,链路层添加一些首部信息组成链路层帧,然后交给物理层传输。

接收方:物理层接收到信息,传递给链路层,链路层校验首部信息,将拆分后的数据报传递给网络层,网络层校验首部信息,将拆分后的报文段传递给运输层,运输层校验首部信息,将拆分后的报文传递给应用层(通过 Socket)。

应用层

应用层主要有 HTTP、SMTP、FTP 三种协议。

HTTP

HTTP 使用 TCP 作为它的支撑运输协议,客户端首先与服务端建立 TCP 连接,建立完成后客户端向套接字写入 HTTP 请求报文,服务端向套接字读取 HTTP 请求报文,处理完成后向套接字写入 HTTP 响应报文。由于 TCP 提供了可靠数据传输,因此 HTTP 协议不必要考虑数据丢失等问题。

持续连接和非持续连接

HTTP 协议支持持续连接和非持续连接。

向服务端发送多个请求,如果每次请求都经不同的 TCP 连接发送,那么就是不持续连接,如果每次请求都经相同的 TCP 连接发送,那么就是持续连接。

很明显,非持续连接的效率不高,每次都要去新建 TCP 连接,不但会给服务器带来压力,同时通信时延也相应加长了。注:OkHttp 就是使用了持续连接,来杜绝这两个问题。

报文格式

一个典型的 HTTP 请求报文如下:

GET /somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
Accept-language: fr

(data data data data ...)

请求报文第一行叫作请求行,后继的行叫作请求头,接着是一个空行,然后是请求体。

请求行有如下几个字段:

  1. 方法字段。
  2. URL 字段。
  3. HTTP 版本字段。

请求头有如下几种:

  1. HOST 指定目标主机,虽然 TCP 连接已经确定了目标主机地址,但这却是 Web 代理高速缓存所需要的。
  2. Connection 告知服务端是否需要保持持续连接,可选值为 keep-alive、close 。
  3. User-agent 网络请求工具类型。
  4. Accept-language 声明可以理解的语言。
  5. If-Modified-Since 配合响应头 Last-Modified,如果服务端判断文件最后修改地址相同那么返还 304。

一个典型的 HTTP 响应报文如下:

HTTP/1.1 200 OK
Connection: close
Date: Tue, 18 Aug 2015 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 18 Aug 2015 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html

(data data data data ...)

响应报文第一行叫作响应行,后继的行叫作响应头,接着是一个空行,然后是响应体。

响应行有如下几个字段:

  1. HTTP 版本字段。
  2. 响应码。
  3. 响应码描述。

常见的响应码有如下几种:

200:表示请求成功。

301、302、303、307、308:重定向。

400:请求不能被服务端理解。

404:请求的文件不在服务器上。

500:服务器内部错误。

505:请求的 HTTP 版本不支持。

响应头有如下几种:

  1. Connection 告知客户端是否保持持续连接,可选值为 keep-alive、close 。

  2. Date 服务端发送响应报文的日期和时间。

  3. Server 服务端服务器类型。

  4. Last-Modified 文件最后修改时间。

  5. Content-Length 响应体字节数。

  6. Content-type 响应体类型。

SMTP

与 HTTP 一样,SMTP 同样也是将 TCP 作为其运输协议。

假设 Alice 想给 Bob 发送一封简单的 ASCII 报文流程如下:

  1. Alice 使用其邮件代理程序撰写报文,提供 Bob 的邮件地址,然后进行发送。
  2. Alice 的邮件代理程序发送给 Alice 的邮件服务器,在那里报文被放在报文队列中。
  3. 运行在 Alice 邮件服务器在的 SMTP 客户端发现了报文队列中的该报文,就创建一个到运行在 Bob 邮件服务器的 SMTP 服务端的 TCP 连接。
  4. 在 Bob 的邮件服务其上,SMTP 服务端接收到该报文,将其放入 Bob 的邮箱中。
  5. 在 Bob 方便的时候使用其邮件代理程序查看邮件。

传输层

传输层主要有 UDP、TCP 两种协议。

UDP(用户数据报协议)为调用它的应用程序提供了一种不可靠、无连接的服务,TCP(传输控制协议)为调用它的应用程序提供了一种可靠的、面向连接的服务。

TCP 通过校验和、确认应答+序列号、超时重传等方式实现可靠数据传输。 其还提供了流量控制(接收端只允许发送端发送缓冲区能容纳的数据)、拥塞控制(慢启动,下载时速度也是从慢到快)。

三次握手

  1. 客户端发送 SYN 报文段 SYN 位置为 1 ,序号字段为 X。
  2. 服务端返回 SYNACK 报文段 SYN、ACK 位置为 1,序号字段为 Y,确认字段为 X + 1。
  3. 客户端发送 ACK 报文段 ACK 位置为1,确认字段为 Y + 1。

为什么不能两次握手?

两次握手,服务端的初始序列号就没法被确认,两者间序号就不同步了,这时候如果服务端要发消息给客户端就搞不明白用哪个初始序号。

四次挥手

  1. 客户端发送 FIN 报文段。
  2. 服务端发送 ACK 报文段。
  3. 服务端发送 FIN 报文段。
  4. 客户端发送 ACK 报文段。

多路分解

将运输层报文段的数据交付到正确的套接字的工作叫多路分解。

UDP 解包后根据目标端口号分发给对应的套接字。

TCP 解包后根据四元组(源IP地址、源端口号、目标IP地址、目标端口号)分发给对应的套接字。

多路复用

从多个套接字中收集数据块,并为每个数据块封装上首部信息,生成报文段,然后将报文段传递给网络层。这些工作叫多路复用。

HTTPS

与 HTTP 的明文传输相比较,HTTPS 使用 SSL / TSL 进行加密,大大提高了数据传输的性能,不过由于多了加密这一步骤所以性能比 HTTP 稍差。

加密方式

加密方式分为对称加密以及非对称加密,加密解密的秘钥都是一样的就是对称加密,否则就是非对称加密,因此使用公钥、私钥的就是非对称加密。对称加密算法有 DES 等,非对称加密算法有 RSA 等。

公钥和私钥

无法根据已知的公钥推断出私钥,但是可以根据已知的私钥推断出公钥,使用公钥加密的明文只能使用对应的私钥进行解密,反之亦然。

通信原理

如果客户端拥有公钥,那么客户端就可以使用公钥加密来安全的向服务端发送消息(因为只有对应的私钥才能解开,而私钥只有服务端有),但是问题来了,服务端给客户端的响应是使用私钥进行加密的,如果第三方也有公钥,那么它不是获取响应内容了,如果内容是用户的敏感信息怎么办?因此光靠一对公钥私钥是没办法做到安全通信的。

基于上述原因要做到安全通信一般采用非对称加密结合对称加密,可以让客户端生成一个对称密钥,然后使用公钥加密发送给服务端,服务端接收到密钥后,后续所有响应全部使用该密钥进行加密(实际是使用密钥的 hash 值加密)。这样通行就安全了,因为第三方无法获取对称密钥。

上述情况都是建立在客户端拥有服务端的公钥情况下,但是客户端是如何获取公钥的呢?考虑以下两种方式:

  1. 将公钥放到一个指定网站上,要求客户端在通信前进行下载。
  2. 在与客户端开始通信时,将公钥发送给客户端。

上述两种方式都有问题,黑客完全可以拦截 Http 响应让你获取到一个假的公钥,客户端也没办法验证。

为了解决这个问题,数字证书就诞生了,证书内容包含:

  1. 证书的发布机构。
  2. 证书的有效期。
  3. 证书所有者。
  4. 公钥。
  5. 签名所使用的算法。
  6. 指纹以及指纹算法。

客户端可以根据证书校验这个证书是否是服务端的,因此首次通信时服务端给客户端证书就可以保证通信安全了。

那么客户端是如何校验这个证书就是服务端的?

  1. 申请证书时 CA 机构会先创建一对公钥私钥,将公钥写入证书。
  2. 然后会根据指纹算法(md5、sha1等)计算证书的指纹。
  3. 接着用其私钥根据签名算法对指纹和指纹算法进行加密。
  4. 接着将该加密后的信息存入证书,然后给申请方该证书以及一个私钥。
  5. 服务端下发证书给客户端,客户端查看该证书的根证书是否在自己的信任根证书列表中,如果有那么取出公钥及签名算法,对服务端下发的证书的指纹及指纹算法进行解密,解密后客户端再使用指纹算法计算证书的指纹,如果对的上,那么就表示没被篡改。不过没被篡改不一定就是服务端的,还得将当前访问的网址与证书中记载的网址进行比对,一致才能确定。
  6. 如果证书中的机构不在操作系统的受信任证书中,那么就会出错,因为使用不受信任的证书很危险。

基于上述,来分析下 Https 的原理。

首先先进行握手。

  1. Client Hello,将客户端支持的密钥算法套件(支持的 SSL 或 TSL 版本、对称加密算法、非对称加密算法、Hash 算法)发送给服务端。
  2. Server Hello,服务端选取双方都支持的第一个密钥算法套件,返回给客户端。比如:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) 表示协议使用 TLS,使用 ECDHE、RSA 作为密钥交换算法,加密算法是AES,Hash 算法( MD5 或者 SHA 256)。
  3. Certificate, 服务端发送证书给客户端。
  4. Server Hello Done。服务端发送信息完毕。
  5. 客户端拿到证书对证书所有者、有效期等信息进行一一校验,然后看该证书的根证书是否在自己的信任根证书列表中,如果有那么取出公钥及签名算法,对服务端下发的证书的指纹及指纹算法进行解密,解密后客户端再使用指纹算法计算证书的指纹,如果对的上,那么就表示没被篡改。
  6. 客户端生成随机数,作为对称加密密钥通过公钥加密发送给服务端,服务端通过私钥解密获取对称加密密钥。
  7. 然后双方就使用该对称加密密钥进行信息传递。
0%