计算机网络的一些知识


https

http数据明文传输不安全,所以要有加密算法,如对称加密(可以使用一个密钥加密解密数据):

image-20211119123920909

问题是对称加密,密钥怎么安全传输,密钥泄露了何谈加密?有了非对称加密,公钥加密,只能私钥解密;私钥加密,只能公钥解密。

原理图:

image-20211119122612374

https通信过程分为两大阶段:证书验证和数据传输阶段。

采用https协议的服务器需要有CA证书(Certification Authority)证书。需要申请然后专门的机构颁发。颁发证书同时会产生公钥和私钥,私钥服务器留着,公钥附带在证书信息中,公开。证书本身带电子签名,防止篡改。

客户端请求https网址https://orzlinux.cn,服务器响应请求,将证书给客户端,证书里面有公钥和其它信息。点击url旁边的锁可以查看:

image-20211119123603615

客户端解析证书进行验证。如果证书没有问题,就会从中去除服务器公钥,如上图所示。然后客户端生成一个随机码KEY,使用公钥加密,发送给服务器,作为后面对称加密的密钥。服务器收到KEY之后用私钥解密。这样就解决了对称加密的密钥泄露问题。之后服务器和客户端就可以利用KEY进行对称加密,传输数据。

url解析过程

  1. 域名解析(域名 www.orzlinux.cn 变为 ip 地址)。

    浏览器搜索自己的DNS缓存(维护一张域名与IP的对应表);若没有,则搜索操作系统的DNS缓存(维护一张域名与IP的对应表);若没有,则搜索操作系统的hosts文件(维护一张域名与IP的对应表)。

    若都没有,则找 tcp/ip 参数中设置的首选 dns 服务器,即本地 dns 服务器(递归查询),本地域名服务器查询自己的dns缓存,如果没有,则进行迭代查询。将本地dns服务器将IP返回给操作系统,同时缓存IP。

  2. 发起 tcp 的三次握手,建立 tcp 连接。浏览器会以一个随机端口(1024-65535)向服务端的 web 程序 80 端口发起 tcp 的连接。

  3. 建立 tcp 连接后发起 http 请求。

  4. 服务器响应 http 请求,客户端得到 html 代码。服务器 web 应用程序收到 http 请求后,就开始处理请求,处理之后就返回给浏览器 html 文件。

  5. 浏览器解析 html 代码,并请求 html 中的资源。

  6. 浏览器对页面进行渲染,并呈现给用户。

Cookie、Session

Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。

Cookie 主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Session是服务器端使用的一种记录客户端状态的机制。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。

分布式Session

在互联网公司为了可以支撑更大的流量,后端往往需要多台服务器共同来支撑前端用户请求,那如果用户在 A 服务器登录了,第二次请求跑到服务 B 就会出现登录失效问题。

分布式 Session 一般会有以下几种解决方案:

  • 客户端存储:直接将信息存储在cookie中,cookie是存储在客户端上的一小段数据,客户端通过http协议和服务器进行cookie交互,通常用来存储一些不敏感信息

  • Nginx ip_hash 策略:服务端使用 Nginx 代理,每个请求按访问 IP 的 hash 分配,这样来自同一 IP 固定访问一个后台服务器,避免了在服务器 A 创建 Session,第二次分发到服务器 B 的现象。

  • Session 复制:任何一个服务器上的 Session 发生改变(增删改),该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点。

  • 共享 Session:服务端无状态话,将用户的 Session 等信息使用缓存中间件(如Redis)来统一管理,保障分发到每一个服务器的响应结果都一致。

建议采用共享 Session的方案。

tcp粘包

udp不拆分合并消息,没有粘包一说。

硬核图解|tcp为什么会粘包?背后的原因让人暖心

总结:其实并不是tcp粘包,而是应用层处理的时候怎么分开不同的消息包,tcp面向字节流,不知道具体消息的界限,导致粘包的发生。

应用程序单次读到了不完整的包属于拆包

比如socket.read(buf)时,读到的buf不完整

应用程序单次读到了预期之外的数据,属于粘包

比如socket.read(buf)时,读到的buf内包含其他数据。

netty里面的websocket应该是已经自动做好处理了。

chunked

不依赖头部的长度信息,也能知道实体的边界——分块编码。数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。

  1. 在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。
  2. 每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF。
  3. 最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束。

tcp rst

在TCP协议中,rst段标识复位,用来异常的关闭连接。在TCP的设计中它是不可或缺的,发送rst段关闭连接时,不必等缓冲区的数据都发送出去,直接丢弃缓冲区中的数据。而接收端收到rst段后,也不必发送ack来确认。

正常情况下,不管是发出,还是收到置了这个标志位的数据包,相应的内存、端口等连接资源都会被释放。从效果上来看就是TCP连接被关闭了。

而接收到 RST的一方,一般会看到一个 connection resetconnection refused 的报错。

image-20211119151116671

出现场景:

  • 端口不可用:
    • 端口未监听
    • 程序启动了但是崩了:如服务端做监听操作的应用崩了,服务器内核协议栈在收到客户端首席,就会回一个rst。
  • socket提前关闭:
    • 本端提前关闭:如果本端socket接收缓冲区还有数据未读,此时提前close() socket。那么本端会先把接收缓冲区的数据清空,然后给远端发一个RST。
    • 远端已经close()socket,此时本端还尝试发数据给远端。那么远端就会回一个RST。

RST,不需要ACK确认包

rst攻击:正常情况下客户端服务端双方可以通过RST来断开连接。假设不做seq校验,如果这时候有不怀好意的第三方介入,构造了一个RST包,且在TCP和IP等报头都填上客户端的信息,发到服务端,那么服务端就会断开这个连接。同理也可以伪造服务端的包发给客户端。这就叫RST攻击

实际消息发送过程中,接收窗口是不断移动的,seq也是在飞快的变动中,此时第三方是比较难构造出合法seq的RST包的,那么通过这个seq校验,就可以拦下了很多不合法的消息。

服务端在已连接(ESTABLISHED)状态下,如果收到客户端发来的第一次握手包(SYN),会怎么样?

当客户端发出一个不在合法窗口内的SYN包的时候,服务端会发一个带有正确的seq数据ACK包出来,这个ACK包叫 challenge ack。在获得这个challenge ack后,攻击程序就可以以ack值为基础,在一定范围内设置seq,这样造成RST攻击的几率就大大增加了。

参考

HTTPS 详解一:附带最精美详尽的 HTTPS 原理图

HTTPS 详解二:SSL / TLS 工作原理和详细握手过程

计算机网络

cookie和session的详解与区别

细说 Netty 中的粘包和拆包

分块编码(Transfer-Encoding: chunked)

tcp rst产生的几种情况

动图图解!收到RST,就一定会断开TCP连接吗?