网络是怎么连接的 第五章 防火墙

23 阅读21分钟

防火墙有很多种策略,最常用的是包过滤。

sec1 防火墙包过滤

下面是一个包过滤的规则。但是有一些问题

image.png

第三条防火墙规则我觉得有问题,如果要禁止subnet内部的server 建立TCP连接到外网,应该限制接收方端口号,比如80和443 port

  • 服务器或客户端在 192.0.2.0/24 内部运行,尝试对外部目标(如公网的 Web 服务器)建立 TCP 连接时,连接请求(SYN 数据包)会被阻止。
  • 由于大多数 HTTP 和 HTTPS 请求默认使用目标端口 80 或 443,这样的规则可以阻止常见的 Web 通信。

更严格的限制方案:如果需要全面阻止子网内的所有 TCP 连接,可以设计规则:destination *;80port; SYN=1 ACK=0 进行deny。

server 80端口会不会过于拥挤

这是一个非常好的问题!让我们逐步解释为什么 成千上万个客户端可以同时连接到服务器的 80 端口,而服务器的 80 端口仍然能够瞬间响应所有客户端。问就是不会,因为80 port 有一个固定的sockert 监听, 如果有新的client连接,会创建新的socket 使用新的port 和client 进行通信。

1. TCP 的四元组机制

每个 TCP 连接通过以下四元组唯一标识:

  • 源 IP 地址:客户端的 IP。
  • 源端口号:客户端随机分配的端口(动态端口)。
  • 目标 IP 地址:服务器的 IP。
  • 目标端口号:服务器的监听端口(如 80)。

虽然所有客户端的目标端口都是服务器的 80 端口,但每个客户端的 源端口源 IP 是唯一的,因此服务器能够同时区分成千上万的连接。


2. 服务器的 80 端口如何工作?

(1) 监听套接字

服务器的 80 端口通过一个监听套接字(Listening Socket)来侦听所有到达的连接请求。监听套接字只负责接收新的连接请求。

  • 当客户端发送 SYN 包发起连接时,服务器的监听套接字接受这个连接,并生成一个新的套接字用于后续通信。

(2) 新的通信套接字

服务器为每个成功建立的连接创建一个新的通信套接字。这个新的套接字由以下四元组唯一标识:

  • 客户端的 源 IP
  • 客户端的 源端口
  • 服务器的 目标 IP
  • 服务器的 目标端口(固定为 80)

即使所有客户端的目标端口都是服务器的 80 端口,不同的客户端连接都会被分配到独立的套接字。


3. 并发处理的关键:多路复用机制

为了能够同时处理成千上万的客户端连接,服务器会使用操作系统提供的多路复用机制。以下是关键技术:

(1) 多路复用(IO Multiplexing)

  • 操作系统的网络堆栈可以通过 epoll(Linux)、kqueue(BSD)、select、或 poll 等系统调用来同时监听多个套接字上的事件(如新的数据到达、连接关闭等)。
  • 监听套接字负责接收新的连接请求。
  • 通信套接字负责处理已经建立的连接。

(2) 多线程或异步处理

现代 HTTP 服务器(如 Nginx、Apache 或 Node.js)通常采用以下机制之一来高效处理并发:

  1. 多线程/多进程

    • 每个线程或进程可以处理一个独立的客户端连接。
    • 这种方式适用于 CPU 密集型任务,但对于成千上万的连接可能导致资源消耗过大。
  2. 事件驱动的异步处理

    • 如 Nginx 或 Node.js,使用事件循环和异步 IO 来高效处理大量连接。
    • 单个线程可以通过非阻塞 IO 同时处理多个连接。

在互联网(公网)中,私有 IP 地址(如 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)被保留用于局域网内部通信,互联网路由器的路由表中不会包含这些私有地址的路由信息。因此,任何包含私有地址作为源 IP 或目标 IP 的数据包,在经过互联网中的路由器时都会被丢弃。这就是为什么在私有网络与公网之间通信时,必须使用网络地址转换(NAT)技术,将私有 IP 地址转换为公网 IP 地址,以确保数据包能够在互联网中正确传输。

包过滤规则主要基于数据包的头部信息(如源 IP 地址、目标 IP 地址、源端口、目标端口和协议类型)进行检查和过滤。它们不分析数据包的负载部分,即无法检测数据包的具体内容。因此,包过滤防火墙无法识别或阻止基于数据内容的攻击或威胁。

sec2 负载均衡

client 很多,发送的请求不能都让一台server 处理,第一种方法就是架设多个web server 然后前端使用load balancer 进行routing. 这种架构统称为分布式架构, 我之前一直以为分布式架构就是去中心化架构,看来是理解错了。

DNS round-robin 轮询方式

如果没有专门的负载均衡设备,靠DNS实现负载均衡,使用轮询策略(round-robin), 通过这种方式可以将访问平均分配给所有的服务器。当访问服务器时,客户端需要先向 DNS 服务器查询服务器的 IP 地址,如果在 DNS 服务器中填写多个名称相同的记录,则每次查询时 DNS 服务器都会按顺序返回不同的 IP 地址。

举个例子: 对于域名 www.lab.glasscom.com, 如果我们给它分配如下 3 个 IP 地址 192.0.2.60
192.0.2.70
192.0.2.80

每次查询DNS 会依次把IP给返回, 比如,当第 1 次查询这个域名时,服务器会返回如下内容:
192.0.2.60
192.0.2.70
192.0.2.80

当第 2 次查询时,服务器会返回如下内容
192.0.2.70
192.0.2.80
192.0.2.60

当第 3 次查询时,服务器会返回如下内容
192.0.2.80
192.0.2.60
192.0.2.70

如下图所示,

  • A记录 只能将域名映射到 IPv4 地址。

  • 当一个域名有多个服务器时,可以为同一个域名配置多个 A 记录,提供负载均衡或冗余

image.png

浏览器在接收到多个 IP 地址后,通常会尝试与列表中的第一个 IP 地址建立连接。如果连接失败,浏览器可能会尝试下一个 IP 地址,直到成功建立连接或列表耗尽。

缺点: 没有probe 来探测服务器的活性

  1. 假如多台 Web 服务器中有一台出现了故障, 这时我们希望在返回 IP 地址时能够跳过故障的 Web 服务器,然而普通的 DNS 服务器并不能确认 Web 服务器是否正常工作,因此即便 Web 服务器 宕机了,它依然可能会返回这台服务器的 IP 地址
  2. 没有配置session persistance,不过这个是在load balancer 中配置的

使用专门负载均衡设备

首先要用负载均衡器的 IP 地址代替 Web 服务器的实际 地址注册到 DNS 服务器上。也就是使用app gateway frontend IP 代替实际的web server 多台IP。

HTTP 被设计为一种无状态协议,这意味着每个请求都是独立的,服务器不会自动保留先前请求的上下文信息。因此,服务器无法仅通过 HTTP 协议判断当前请求是否与之前的请求相关。

负载均衡服务器的作用就是把请求分发给多个后台server

除了使用多台功能相同的 Web 服务器分担负载之外,还有另外一种方法,就是将整个系统按功能分成不同的服务器 ,如 Web 服务器、数据库服务器。缓存服务器就是一种按功能来分担负载,它是另一种让系统处理大规模请求的方式。

sec3 缓存服务器

反向代理

缓存服务器是一台通过代理机制对数据进行缓存的服务器。代理介于 Web 服务器和客户端之间,具有对 Web 服务器访问进行中转的功能。按照它所在的位置不同,可以分为反向代理和正向代理,他们分别位于server端和client端。

它可以将 Web 服务器返回的数据保存在磁盘中,并可以代替 Web 服务器将磁盘中的数据返回给客户端

缓存服务器 工作流程如下

来自客户端的 访问中,总有一部分访问可以无需经过 Web 服务器,而由缓存服务器直接 处理

缓存没有命中

有点类似缓存击穿;指的是某个数据的缓存失效,而该数据恰好是高并发访问的热点数据。当该热点数据被并发请求时,由于缓存失效(或没有缓存),所有请求都会直接查询数据库,导致数据库压力剧增,甚至崩溃。

在这里就是缓存服务器没有数据,把请求转发给web server. web server 要发送全量的数据。下图的a (2) image.png

缓存server 转发 请求给web server; Via 这个字段一般大概率会出现在http header; 我们能从web server获取的请求上找到via字段;

image.png 缓存server 转发response  给  client   也会带有via字段在header 说明这个response其实来自cache server

image.png

缓存命中

当缓存服务器发现客户端请求的数据命中缓存时,也是会发送请求到web server, 但是不会像上面一样要求使用全亮的数据; 它通常会执行以下操作来确保数据的一致性

工作流程:

  1. 缓存命中: 缓存服务器检查自己的缓存,发现有与客户端请求匹配的数据。
  2. 验证缓存有效性: 缓存服务器会向 Web 服务器发送一个验证请求,以确定缓存的数据是否仍然是最新的。
    • 这个验证请求通常会包含以下 HTTP 头部:
      • If-Modified-Since:缓存的内容最后一次修改的时间。
      • ETag:缓存内容的唯一标识符(由服务器生成,用于验证数据是否更改)。
    • 这些头部告诉 Web 服务器:只有当缓存的数据发生变化时,才需要返回新的数据。
  3. Web 服务器响应:
    • 如果数据没有变化: Web 服务器返回 HTTP 状态码 304 Not Modified,表示数据未修改,缓存服务器可以直接使用已有的缓存数据。
    • 如果数据已经变化: Web 服务器返回最新的数据,缓存服务器用新的数据更新缓存并将其返回给客户端。
  4. 响应客户端: 缓存服务器根据 Web 服务器的响应,决定是使用本地缓存还是更新缓存后返回最新内容。

为什么需要这样做?

  • 数据一致性: 确保客户端获取到的内容是最新的,避免用户看到过期或错误的数据。
  • 提升性能: 即使缓存服务器需要验证数据有效性,验证的开销通常比直接返回整个资源的开销小得多。例如:
    • 如果数据未变更,Web 服务器仅返回 304 状态,而不需要传输完整数据。
    • 节省网络带宽。
  • 遵守缓存策略: 根据 HTTP 协议,缓存服务器需要遵循缓存控制头(如 Cache-ControlETag 等)来决定何时验证或刷新缓存。

举一个例子示例

客户端请求某个资源 /data.json,缓存服务器发现命中缓存,发起验证请求:

GET /data.json HTTP/1.1
Host: www.example.com
If-Modified-Since: Wed, 22 Nov 2024 08:00:00 GMT
ETag: "abc123"

Web 服务器响应:

  • 数据未变更:

    HTTP/1.1 304 Not Modified
    

    缓存服务器直接返回缓存数据给客户端。

  • 数据已变更:

    HTTP/1.1 200 OK
    Content-Type: application/json
    Content-Length: 1234
    ETag: "def456"
    
    {"new": "updated data"}
    

    缓存服务器更新缓存,并将最新数据返回给客户端。

上述的缓存服务器如果放在web server,就可以称之为反向代理。反向代理(Reverse Proxy)是指在 Web 服务器前面部署一个代理服务器,它接收客户端的请求,然后转发到一个或多个后台服务器进行处理,之后再将处理结果返回给客户端。反向代理前面应该还有一个防火墙,这是本章第一部分的内容。

正向代理(forward proxy)

下面是正向代理 的架构图

正向代理架设在client侧

image.png

由于代理在转发过程中可以查看请求的内容,所以可以根据内容判断是否允许访问。也就是说,通过代理可以禁止员工访问危险的网站,或者是与工作内容无关的网站

这个和我之前做的工单很类似,客户之所以无法上传attachment 到boards Work Item , 并且告诉权限不够401,就是他们的内网正向代理阻挡了敏感的信息传递。

在使用正向代理时,浏览器的请求行为会发生变化。以下是详细解释:

  1. 未使用正向代理时:

    • 请求目标: 浏览器直接与目标网站的服务器通信。

    • 请求内容: 浏览器从地址栏中提取目标服务器的域名和路径。

    • 请求格式: 在 HTTP 请求的 URI 字段中,仅包含路径部分。

    • 示例:

      GET /index.html HTTP/1.1
      Host: www.example.com
      
    • 解释:

      • GET /index.html HTTP/1.1:请求目标服务器的 /index.html 文件。
      • Host: www.example.com:指定目标服务器的域名。
  2. 使用正向代理时:

    • 请求目标: 浏览器将所有请求发送给配置的代理服务器。

    • 请求内容: 浏览器在请求的 URI 字段中包含完整的 URL。

    • 请求格式: 在 HTTP 请求的 URI 字段中,包含完整的目标 URL。

    • 示例:

      GET http://www.example.com/index.html HTTP/1.1
      Host: www.example.com
      
    • 解释:

      • GET http://www.example.com/index.html HTTP/1.1:请求代理服务器访问完整的目标 URL。

      • Host: www.example.com:指定目标服务器的域名。

正向代理的使用方式 : 这个方式比较繁琐,所以后续出现反向代理代替

使用正向代理时,一般需要在浏览器的设置窗口中的“代理服务器”一栏中填写正向代理的IP 地址

在 HTTP 协议中,Connection: Keep-Alive 头部用于请求或指示保持当前的 TCP 连接,以便在同一连接上发送多个请求和接收多个响应。

HTTP/1.0 与 HTTP/1.1 的差异:

  • HTTP/1.0: 默认情况下,每个请求/响应对后都会关闭连接。要启用持久连接,客户端需要在请求头中包含 Connection: Keep-Alive,服务器在响应中也需要包含相同的头部。
  • HTTP/1.1: 持久连接是默认行为,连接会保持打开状态,除非明确指定关闭。因此,在 HTTP/1.1 中,通常不需要使用 Connection: Keep-Alive 头部来请求持久连接。

关于“Session Persistence”:

“Session Persistence” 通常指在负载均衡环境中,将同一用户的所有请求路由到同一后端服务器,以保持会话状态。Connection: Keep-Alive 头部与此概念无关。它仅涉及在客户端和服务器之间保持 TCP 连接,以减少连接建立的开销,提高通信效率。

透明代理

如果请求消 息有多条路径可以到达 Web 服务器,那么就必须在这些路径上都放置透明 代理,因此一般是将网络设计成只有一条路可以走的结构,然后在这一条 路径上放置透明代理

CDN 内容分发网络服务器

CDN(内容分发网络)并不完全等同于正向代理,但它与正向代理有一定的相似性。CDN 的本质是将网站内容(如静态资源)缓存到全球各地的节点(代理服务器),当客户端请求资源时,会从距离用户最近的缓存节点获取,而不是直接从源 Web 服务器获取,这样可以减轻源服务器的负载,减少延迟,提高访问速度。

  1. 反向代理缓存服务器放在服务器端时,可以减轻 Web 服务器的负载, 但无法减少互联网中的流量;如果要减少网络拥塞可以使用正向代理 2. 但是正向代理,不受server 侧的开发人员配置 于是就有专门的人销售CDN服务,其实就是售卖架设在client侧的 正向代理服务,顺便可以让你配置

CDN返回最近的缓存服务器的IP 

CDN(内容分发网络)的主要作用之一确实是通过智能调度,将客户端的请求引导至距离最近或最优的缓存服务器,以提高访问速度和用户体验。然而,CDN的功能不仅限于此,还包括:

内容缓存:将网站的静态资源(如图片、视频、CSS、JavaScript等)缓存到分布在各地的边缘服务器上,使用户可以就近获取所需内容,减少对源站服务器的压力

为了更直观地理解上述过程,以下通过一个具体例子来说明如何利用路由器的路由表信息估算客户端与缓存服务器之间的距离,从而将用户请求引导至最近的缓存服务器。

场景设置:

  • CDN系统在四个城市(A市、B市、C市、D市)各部署了一台缓存服务器,分别连接到各自的路由器:路由器A、路由器B、路由器C和路由器D。

  • 每台路由器都有一张路由表,记录了到达其他网络节点的路径信息。

  • DNS服务器收集了这四台路由器的路由表信息。

  • 一位用户位于E市,使用其本地的客户端DNS服务器发起对某网站的访问请求。

步骤解析:

  1. 收集路由信息:

   - DNS服务器事先从路由器A、B、C、D收集各自的路由表,并将这些信息存储起来。

  1. 接收DNS查询请求:

   - 用户在E市的客户端DNS服务器向CDN的DNS服务器发送域名解析请求。

  1. 查询路由路径:

   - CDN的DNS服务器根据存储的路由表,查询从各路由器(A、B、C、D)到E市客户端DNS服务器的路由路径。

   - 例如,路由器A的路由表显示:通过运营商X到达运营商Y,再到达E市的客户端DNS服务器。

   - 路由器B的路由表显示:直接通过运营商Y到达E市的客户端DNS服务器。

   - 路由器C的路由表显示:通过运营商Z,再到运营商Y,最后到达E市的客户端DNS服务器。

   - 路由器D的路由表显示:通过运营商X到运营商Z,再到运营商Y,最后到达E市的客户端DNS服务器。

  1. 分析路由路径:

   - 通过分析上述路由路径,DNS服务器可以估算每条路径的距离或跳数。

   - 假设直接通过运营商Y的路径(路由器B)最短,其他路径相对较长。

  1. 选择最近的缓存服务器:

   - DNS服务器判断路由器B与E市的客户端DNS服务器之间的路径最短,因此推断部署在B市的缓存服务器距离用户最近。

  1. 返回解析结果:

   - DNS服务器将B市缓存服务器的IP地址返回给E市的客户端DNS服务器。

   - 用户的访问请求被引导至B市的缓存服务器,从而实现快速的内容传输。

HTTP重定向

为了更直观地理解利用HTTP重定向将客户端请求引导至最近缓存服务器的方法,以下通过一个具体例子来说明:

场景设置:

  • 某网站在全球不同地区(如纽约、伦敦、东京)各部署了一台缓存服务器,分别存储相同的静态内容。

  • 用户位于巴黎,首次访问该网站的主页。

传统CDN方法(基于DNS调度):

  1. DNS解析:用户在浏览器中输入网站域名,客户端DNS服务器向权威DNS服务器请求解析该域名。

  2. 智能调度:CDN的权威DNS服务器根据用户的IP地址,判断其地理位置(巴黎),并选择距离最近的缓存服务器(如伦敦)。

  3. 返回IP地址:DNS服务器将伦敦缓存服务器的IP地址返回给客户端。

  4. 内容请求:用户的浏览器直接向伦敦的缓存服务器请求内容。

HTTP重定向方法:

  1. 初始请求:用户在浏览器中输入网站域名,客户端DNS服务器解析域名,返回原始服务器(位于纽约)的IP地址。

  2. 访问原始服务器:用户的浏览器向纽约的原始服务器发送HTTP请求。

  3. 服务器判断:原始服务器接收到请求后,分析请求头中的信息(如IP地址、地理位置),判断用户位于巴黎。

  4. 发送重定向响应:原始服务器返回一个HTTP 302重定向响应,包含Location头部,指向伦敦缓存服务器的URL。

  5. 客户端重定向:用户的浏览器接收到重定向响应后,自动向Location指定的伦敦缓存服务器发送新的HTTP请求。

  6. 获取内容:伦敦缓存服务器处理请求,返回所需的内容给用户。

比较与分析:

  • 传统CDN方法的优点

  - 减少延迟:用户直接与最近的缓存服务器通信,减少了请求的中间环节。

  - 降低原始服务器负担:原始服务器不参与每次请求的处理,减轻了负载。

  • HTTP重定向方法的优点

  - 精确控制:原始服务器可以根据实时的网络状况、服务器负载等因素,动态选择最适合的缓存服务器。

  - 灵活性高:可以根据特定策略(如内容类型、用户权限)进行定制化的重定向。

  • HTTP重定向方法的缺点

  - 增加延迟:用户需要先与原始服务器通信,再被重定向到缓存服务器,增加了一次往返的延迟。

  - 原始服务器负担增加:所有请求都需经过原始服务器的判断和重定向,可能导致其负载增加。

CDN保存原始内容

假设你有一个网站,叫做 example.com,它包含了不同类型的内容。为了提高网站性能和用户体验,你决定使用 CDN 来缓存一些静态资源,减轻 Web 服务器的负担并加速访问速度。

假设你的网站有以下内容:

  • example.com/index.html:首页,包含一些动态生成的内容。
  • example.com/styles.css:页面的 CSS 样式表文件。
  • example.com/logo.png:网站的 logo 图片。
  • example.com/scripts.js:JavaScript 代码,用于页面的交互功能。
  • example.com/videos/tutorial.mp4:一个教学视频。
1. 动态 vs 静态资源
  • 动态资源(例如 index.html)通常不适合缓存,因为它们可能根据用户的请求、时间或其他因素动态生成。例如,如果页面的内容会根据用户的登录状态或请求参数变化,就不应该将 index.html 放入 CDN 缓存。
  • 静态资源(例如 logo.png, styles.css, scripts.js)适合放入 CDN,因为它们通常不经常变化,能够被缓存,并且对所有用户都是相同的。
2. 将静态资源上传到 CDN

将这些静态资源(图片、JS、CSS 等)上传到 CDN 提供商的服务器上。CDN 会将这些文件存储在全球多个缓存节点上。

例如:

  • 用户在 美国 访问 example.com/logo.png,他们的请求会被转发到美国地区的 CDN 节点,获取最快的响应。
  • 用户在 欧洲 访问 example.com/logo.png,他们的请求会被转发到欧洲的 CDN 节点,从而加速加载。
3. 配置 CDN 缓存

通过 CDN 提供的配置接口或控制台,你可以设置缓存策略,指定哪些文件应该缓存,以及缓存的过期时间。例如:

  • 设置 logo.pngstyles.cssscripts.js 缓存 30 天。
  • 设置 tutorial.mp4 缓存 7 天。
  • 设置某些页面缓存时间为 1 天,或者不缓存动态内容。
4. 用户访问的流程:

当一个用户请求 example.com/logo.png 时:

  1. 用户的浏览器向 CDN 发起请求。

  2. CDN 检查是否有缓存的资源。如果缓存存在且未过期,直接返回缓存的资源。

  3. 如果 CDN 没有缓存(例如第一次访问,或者缓存已过期),CDN 会向源服务器请求该资源,缓存返回的内容并将其提供给用户。