/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
网络协议安全笔记(上):链路层 → 传输层
一句话总纲:这套协议设计之初只追求「能通」,认证、完整性、机密性几乎没写进去。所以协议安全的本质就是对着每个协议问三句话:它凭什么相信对方?它拿什么证明数据没被改?它在链路上是明文还是密文?
本文按 链路层 → 网络层 → 传输层 → 应用层 逐层往下走,每个协议固定用同一个模板拆,最后统一收口到「攻击面总表 + 明文可见性 + 简答模板」。
⚠️ 本文只讨论协议原理与原生设计缺陷,用于学习、排障和防御,不包含可直接运行的攻击代码。
本篇范围:0 阅读约定、一 总览、二 链路层、三 网络层、四 传输层(TCP / UDP)。应用层协议与安全总结放在下篇。
0 阅读约定
0.1 每个协议统一按这个模板写
| 名称 / 层级 | 全称、缩写、属于哪一层、上层协议号是多少 |
| 核心作用 | 一句话说清它解决了什么问题(以及不解决什么) |
| 报文结构 | 首部字段、长度、关键字段的坑 |
| 缺陷 | 协议原生设计就缺的东西(不是实现 bug) |
| 利用 | 这些缺陷被组合成了哪些攻击 |
| 防御 | 在哪一层能补上 |
0.2 抓包环境与记号
- 工具:Wireshark,开启 相对序号(Relative sequence number),Seq 从 0 开始显示,不是真实原始序列号。
- Len=0 表示 TCP 载荷为 0,是纯控制报文;Win 是接收窗口;[PSH, ACK] 这类方括号是 Wireshark 的推断标记。
- 「一个以太网帧 = 一个二层包」,绝大多数 DNS 查询/响应单独占一个帧。
一、总览
1.1 TCP/IP 四层 ↔ OSI 七层
| 应用层 | 应用层 + 表示层 + 会话层 | HTTP、HTTPS、DNS、TLS、DHCP、SSH、FTP |
| 传输层 | 传输层 | TCP、UDP |
| 网络层(互联网层) | 网络层 | IPv4、ICMP、IGMP、ARP(跨二三层) |
| 网络接口层(链路层) | 数据链路层 + 物理层 | 以太网、NDP、WiFi、PPP、VLAN |
分层的一句话记忆:
- 链路层解决「同一个广播域里,这一帧交给哪块网卡」→ MAC 地址
- 网络层解决「跨网段,这个包怎么一跳跳送到」→ IP 地址 + 路由
- 传输层解决「到了这台主机,交给哪个进程」→ 端口号
- 应用层解决「这个进程要干什么」→ 业务语义
1.2 封装与解封装

发送方自上而下加头(封装),接收方自下而上剥头(解封装)。三个容易记错的点:
1.3 一次「打开网页」到底用了多少协议
| 1 | 拿到本机 IP | DHCP(UDP 67/68)或静态配置 | DHCP 无认证 → 可被伪造服务器劫持 |
| 2 | 域名换 IP | DNS(UDP 53,必要时 TCP 53) | 无认证 → 缓存投毒、放大攻击 |
| 3 | 查网关 MAC | ARP(以太网 0x0806) | 无认证 → ARP 欺骗、中间人 |
| 4 | 与服务器建连 | TCP 三次握手 | 半连接队列有限 → SYN Flood |
| 5 | 协商加密 | TLS 握手(证书 + 密钥交换) | 证书信任链是唯一身份依据 |
| 6 | 发请求 | HTTP over TLS | 明文 HTTP → 中间人直接读 |
| 7 | 传输中途 | IP 路由、TTL 递减、可能分片 | 源 IP 可伪造、分片可攻击 |
1.4 全文地图
| 二 | 链路层 | 以太网 | MAC 可伪造,交换机只认地址不认人 |
| 二 | 链路层 | ARP | 收到应答就采信,无认证 |
| 三 | 网络层 | IPv4 | 源 IP 可随便填,只校验首部 |
| 三 | 网络层 | ICMP | 谁都能发,早期网络还都放行 |
| 四 | 传输层 | TCP | 握手耗资源,老系统序号可预测 |
| 四 | 传输层 | UDP | 无连接无状态 → 源 IP 伪造零成本,天然适合反射放大 |
| 五 | 应用层 | HTTP | 全明文,不防篡改 |
| 五 | 应用层 | DNS | 原始版本无认证、明文、UDP |
| 五 | 应用层 | TLS/HTTPS | 旧版本漏洞、证书信任体系、SNI 明文 |
二、链路层
这一层的一句话:局域网里没有「身份」,只有「地址」。谁报出自己的 MAC,交换机就照着转发 —— 这就是后面所有二层欺骗的根。
2.1 以太网(Ethernet)
核心作用:在同一个广播域内,用 MAC 地址把数据帧从一块网卡送到另一块网卡。它只管「这一跳」,不管跨网段。
EtherType 字段(以太网头最后 2 字节,用来告诉上层「我装的是什么」):
| 0x0800 | IPv4(最常用,ping、TCP、UDP 都装在这个里面) |
| 0x0806 | ARP |
| 0x8035 | RARP(反向 ARP,现在几乎淘汰) |
| 0x8100 | 802.1Q VLAN 标签帧(带 VLAN) |
| 0x86DD | IPv6 |
| 0x8863 | PPPoE Discovery(拨号发现) |
| 0x8864 | PPPoE Session(拨号数据) |
| 0x8809 | LACP 链路聚合协议 |
两种帧格式:
现代 Ethernet II(DIX):
目的MAC(6B) | 源MAC(6B) | EtherType(2B) | 载荷(46~1500B) | FCS校验(4B)
老式 IEEE 802.3:
目的MAC(6B) | 源MAC(6B) | 长度(2B) | LLC头 | 载荷 | FCS(4B)
区分方法:第 13、14 字节 ≥ 0x0600 → 是 EtherType(Ethernet II);
≤ 0x05DC(1500)→ 是长度字段(802.3)
载荷最小 46B:不够要填充(padding),否则连 64B 最小帧都凑不齐
缺陷
利用
防御:端口安全(限制每口 MAC 数量)、DAI(动态 ARP 检测)、DHCP Snooping、禁用未使用端口、显式配置 trunk、BPDU Guard。
2.2 ARP(Address Resolution Protocol,地址解析协议)
层级:介于网络层与链路层之间,封装在以太网帧里,EtherType = 0x0806。
适用范围:只在同一个广播域(同一个子网)生效。IPv4 局域网专用;IPv6 抛弃了 ARP,改用 NDP(邻居发现协议)。
核心作用:已知目标 IP,查询对应的 MAC 地址。反过来(已知 MAC 查 IP)叫 RARP,已淘汰。
报文结构(28 字节,固定):
| 硬件类型 | 2B | 1 | 以太网 |
| 协议类型 | 2B | 0x0800 | 上层是 IPv4 |
| 硬件地址长度 | 1B | 6 | MAC 6 字节 |
| 协议地址长度 | 1B | 4 | IPv4 4 字节 |
| 操作码 | 2B | 1 = 请求 / 2 = 应答 | |
| 发送方 MAC | 6B | ||
| 发送方 IP | 4B | ||
| 目标 MAC | 6B | 请求时全 0 | |
| 目标 IP | 4B |
工作过程:
补充:免费 ARP(Gratuitous ARP) —— 主机主动广播「我的 IP 对应我的 MAC」,用于 IP 冲突检测和「我换了网卡,大家更新一下」。这一机制本身也常被攻击者用来主动刷新别人的缓存。
实拍:一次 ARP 请求 + 应答(ping 10.41.231.140 触发,过滤器 arp)

- 第 1 条 Who has 10.41.231.140? Tell 10.41.231.117:目的 MAC 是 ff:ff:ff:ff:ff:ff(广播),Target MAC 全 0(还不知道);
- 第 2 条 10.41.231.140 is at 82:48:ed:2e:cd:4a:单播回到我的 MAC,Opcode = reply (2);
- 下方面板里 Sender IP 10.41.231.117 / Target IP 10.41.231.140 就是这次「IP 换 MAC」的全部内容 —— 没有签名,没有校验,也没有「我没问过你别答」。这就是 ARP 欺骗的入口。
缺陷
ARP 协议无身份认证、无校验,主机收到 ARP 应答就直接更新本机 ARP 缓存,不验证这个应答是不是真的目标主机发的,也不要求「我没问过你就别答」。
利用:ARP 欺骗(ARP 中毒)
攻击者发送伪造 ARP 应答:告诉受害者「网关 IP 的 MAC 是我」,同时告诉网关「受害者 IP 的 MAC 是我」。两个方向的流量都经过攻击者主机,实现中间人:抓 HTTP 明文、篡改网页、直接断网。

配套的两个变种:
- ARP 扫描:遍历网段发 ARP 请求,快速发现存活主机(比 IP 扫描更可靠,因为 ARP 不过路由器)。
- ARP 表溢出:灌满主机/交换机 ARP 表,让正常映射被挤掉,被迫重新广播 → 配合伪造应答抢占。
防御:静态 ARP 绑定(arp -s)、ARP 防火墙、DAI(动态 ARP 检测,交换机层面)、划分 VLAN 缩小广播域、重要服务器用静态映射。
DAI 的前提是 DHCP Snooping:交换机要先知道「这个口合法的 IP-MAC 是谁」,才能判断 ARP 应答真假 —— 这是配置题里常考的依赖关系。
2.3 补充:IPv6 的 NDP(一句话)
IPv6 用 NDP(Neighbor Discovery Protocol) 取代 ARP,靠 ICMPv6 的 NS/NA(邻居请求/通告,Type 133/135/136) 实现地址解析,另外还有 RS/RA(路由器请求/通告,Type 133/134)做 SLAAC 自动配置。
安全性同样的坑:NDP 也没有认证 → NS/NA 欺骗(NDP 欺骗)= IPv6 版 ARP 欺骗,防御是 RA Guard / ND Guard。
2.4 补充:VLAN(一句话)
VLAN 在以太网帧里插 4 字节 802.1Q 标签(EtherType 0x8100,里面 12 位 VID 表示 1~4094),把一台交换机的端口逻辑切成多个广播域。
安全含义:VLAN 不是安全边界(很多人误以为是)。跨 VLAN 必须过三层设备,这时候防火墙/ACL 才真正起作用。
三、网络层
这一层的一句话:IP 只负责「尽最大努力把包送到」,所以它不保证送到、不保证顺序、不保证不重复、不保证完整。这些坑全部留给上层去补。
3.1 IP(Internet Protocol,网际协议)
核心作用:寻址 + 路由,完成「主机到主机」的任务。
首部结构(固定 20 字节 + 可变选项):

实际抓包对照(ping 223.5.5.5):

必须记牢的字段:
| 版本 + 首部长度 | 4 + 4 位 | IHL 以 4 字节为单位,5 → 20 字节 |
| 总长度 | 16 位 | 首部 + 数据,最大 65535;抓包里的 Total Length |
| 标识 / 标志 / 片偏移 | 16 / 3 / 13 位 | 分片三件套:同一 ID 属于同一个原始包,MF 表示「后面还有」,片偏移 ×8 表示位置 |
| TTL | 8 位 | 每过一个路由器减 1,减到 0 就丢弃并回 ICMP 超时 → 这就是 traceroute 的原理 |
| 协议号 | 8 位 | 告诉 IP「里面装的是谁」,见下表 |
| 首部校验和 | 16 位 | 只校验首部,不校验数据 |
| 源/目的 IP | 各 32 位 | 源 IP 由发送方自己填 → 可伪造 |
常见协议号:
| 1 | ICMP | 47 | GRE(隧道) |
| 2 | IGMP | 50 | ESP(IPSec 加密载荷) |
| 6 | TCP | 51 | AH(IPSec 认证头) |
| 17 | UDP | 89 | OSPF |
| 41 | IPv6(6in4 隧道) | 132 | SCTP |
分片与 MTU:
- 以太网 MTU = 1500,IP 包超过就要分片;分片可以发生在源主机,也可以发生在中途路由器。
- 接收方靠「标识 + 片偏移 + MF」重组,任一分片丢失 → 整个原始包丢弃。
- DF=1(禁止分片) 时,如果路上 MTU 太小,路由器回 ICMP Type 3 Code 4(需要分片),源主机据此调小 —— 这就是 PMTUD(路径 MTU 发现)。
- 现实中的坑:ICMP 被防火墙全禁 → PMTUD 失效 → 大包发不出去、小包正常,表现为「网页能开但图片加载卡死」。这是运维高频故障,也是考试爱问的点。
实拍:ping -l 3000 被拆成 3 个分片(过滤器 ip.flags.mf == 1 or ip.frag_offset > 0)

三条记录的 Identification 全是 0x9592(表示「我们属于同一个原始包」),Fragment Offset 依次是 0 / 1480 / 2960 字节,前两条 More fragments = 1、最后一条为 0;第 1、2 条被标成 [Reassembled in #3],说明重组是在接收端完成的,中间路由器只负责转发碎片。
缺陷
利用
- IP 源地址伪造:用于 DDoS 反射攻击、扫描时隐藏自身。注意:伪造源 IP 只能「发出去」,收不到回包,所以只适合单向攻击(SYN Flood、反射放大),不能用作正常通信。
- IP 分片攻击:
- Teardrop / 重叠分片:构造片偏移重叠的分片,老系统重组时崩溃;
- 分片绕过 IDS:把攻击载荷切碎,让特征串跨分片,简单 IDS 逐包匹配就失效;
- 微小分片(tiny fragment):第一片只装 8 字节 TCP 头的一部分,逼防火墙无法判断端口。
- TTL 欺骗:伪造较小 TTL 让包提前丢弃,隐藏扫描源(配合 traceroute 探测拓扑)。
防御:入方向 uRPF 反向路由校验(源 IP 是否真的从这条路来)、防火墙过滤、IPsec 加密、分片重组策略(丢弃异常分片)、IDS 做流重组而不是逐包匹配。
IPv6 改善了部分,但基础依然无认证。
补充:IPv6 干了什么(对比表)
| 地址长度 | 32 位 | 128 位 |
| 首部 | 20B + 可变选项 | 固定 40B,选项放扩展头 |
| 首部校验和 | 有 | 取消(交给上下层) |
| 分片 | 路由器可分段 | 只有源主机能分片,用 Fragment 扩展头 |
| 地址解析 | ARP(广播) | NDP(ICMPv6 组播) |
| 自动配置 | DHCP | SLAAC(也可 DHCPv6) |
| 广播 | 有 | 取消广播,改用组播 |
| NAT | 普遍使用 | 设计上不需要(但要隐私仍有 NAT66) |
安全影响:IPv6 没有 NAT 的「伪隔离」,主机直接暴露 → 防火墙必须显式配置;NDP 欺骗、RA 欺骗是 ARP 欺骗的等价物;IPv6 首部无校验和 意味着载荷完整性完全依赖上层。
3.2 ICMP(Internet Control Message Protocol,互联网控制报文协议)
介绍:属于 网络层(IP 层)协议,依附于 IP 协议(协议号 1),封装在 IP 报文中,没有独立的传输端口。
核心作用:传递网络控制信息、差错报告、探测网络状态,不是用来传输业务数据的。
一句话概括:IP 负责送包,ICMP 负责告诉对方:包有没有送到、为什么送不到、网络是否通畅。
一个标准的 ping,链路是【以太网 → IPv4 → ICMP】,不经过传输层。

ICMP 报文结构:Type(1B) + Code(1B) + 校验和(2B) + 4B 头部(随类型变化)+ 数据。
必记的类型/代码:
| 0 / 8 | Echo Reply / Echo Request | 0 | ping 的往返;扫描第一步 |
| 3 | Destination Unreachable | 0 网络 / 1 主机 / 3 端口 / 4 需分片但 DF=1 / 13 管理禁止 | UDP 扫描靠 Code 3(端口不可达)判断端口关闭;Code 4 是 PMTUD |
| 5 | Redirect | 0 网络 / 1 主机 | 让主机改走别的网关 → 伪造可劫持路由 |
| 11 | Time Exceeded | 0 TTL 耗尽 / 1 分片重组超时 | traceroute 的原理 |
| 12 | Parameter Problem | 0 | 首部字段出错 |
| 13 / 14 | Timestamp Request / Reply | 0 | 可探测对端时间 |
| 4 | Source Quench | — | 已废弃(早期拥塞控制) |
ICMPv6 是另一套类型号:1 目的不可达、2 包过大、3 超时、4 参数问题、128/129 Echo、133~137 NDP 五件套。
缺陷
利用
防御:防火墙限制 ICMP 速率、禁止 ICMP 重定向(Redirect 全丢)、阻断 ICMP 隧道(限制载荷大小和频率)、但不要一刀切全禁 —— 会打断 PMTUD。
3.3 补充:IGMP(一句话)
IGMP(Internet Group Management Protocol,协议号 2)用来管理组播组成员:主机告诉本地路由器「我要加入/退出某个组播组」,路由器据此决定往这个网段转发哪些组播流。IPTV、视频会议用它。安全上关注 IGMP 报文伪造导致组播流量泛洪。
四、传输层
这一层的一句话:网络层只管把包送到主机,传输层靠端口把数据交给进程;同时只有这一层开始,才出现「可靠性」这个话题。
4.0 端口(一句话带过)
端口 0~65535,用来在同一台主机内区分不同进程;TCP 端口和 UDP 端口是两个独立的编号空间(53/UDP 和 53/TCP 是两个不同的东西,DNS 同时用)。五元组 源IP, 源端口, 目的IP, 目的端口, 协议 唯一标识一条连接。
详细内容(知名端口划分、Socket、C/S 模型)见同目录《Web安全基础.md》的「前置知识」一节,这里不重复。
4.1 TCP(Transmission Control Protocol,传输控制协议)
核心作用:在不可靠的 IP 之上,提供面向连接、可靠、有序、有流量控制和拥塞控制的字节流服务。
首部结构(固定 20 字节 + 最多 40 字节选项):

关键字段:
| 序号 Seq | 本报文数据第一个字节的编号 | 32 位回绕;SYN/FIN 各占 1 个序号 |
| 确认号 Ack | 期望收到的下一个字节 = 对方 Seq + 对方数据长度 | 只对 ACK=1 的报文有效 |
| 数据偏移 | 首部长度,单位 4 字节 | 有选项时 > 5 |
| 标志位 | URG ACK PSH RST SYN FIN + CWR ECE | PSH = 尽快交给应用层;RST = 直接断连 |
| 窗口 Win | 接收方还能收多少字节 | 16 位不够用 → 靠 WS 选项左移放大 |
| 校验和 | 伪首部 + 首部 + 数据 | 与 IP 首部校验和分工不同 |
三次握手 / 四次挥手(实拍抓包)

| 10350 | [SYN] | 客户端发起连接(握手第 1 步) |
| 10351 | [SYN, ACK] | 服务端应答(握手第 2 步) |
| 10352 | [ACK] | 客户端确认,连接建立(握手第 3 步) |
| 10353 | HTTP GET | 发送 HTTP GET 请求 |
| 10367 | [PSH, ACK] | 推送数据 |
| 10369 | HTTP/1.1 200 OK | 服务器返回 JSON 响应 |
| 10372 | [FIN, ACK] | 客户端主动关闭连接 |
| 10379 | [FIN, ACK] | 服务端关闭 |
| 10385 | [ACK] | 最后确认,连接断开 |
TCP 抓包分析(HTTP GET 示例)
环境:Wireshark,开启相对序号,Seq 从 0 开始显示,不是真实原始序列号
- 客户端:192.168.1.59:1896(本机,随机端口)
- 服务端:44.206.195.5:80(httpbin,HTTP 80 端口)
- 浏览器访问 http://httpbin.org/get 的包
核心规则:
Ack 号 = 对方上一个 Seq + 对方报文携带的数据长度
✅ SYN / FIN 标志本身占用 1 个序号,即使载荷 Len=0
一、TCP 三次握手(建立连接)
| 1896 → 80 | [SYN] Seq=0 Win=65535 Len=0 | 客户端发起连接请求,初始序号 0,无应用数据 |
| 80 → 1896 | [SYN,ACK] Seq=0 Ack=1 Win=26883 Len=0 | 服务端确认收到 SYN(Ack=0+1=1),同时发起自己的连接请求 |
| 1896 → 80 | [ACK] Seq=1 Ack=1 Win=65280 Len=0 | 客户端确认收到服务端 SYN(Ack=0+1=1) |
✅ 三次握手完成,TCP 通道就绪,可以传输上层 HTTP 数据。
二、HTTP 业务数据传输
| 1896 → 80 | GET /get HTTP/1.1 | 客户端发送 GET 请求,TCP 载荷 79 字节,带 PSH,ACK;PSH:通知内核尽快把数据交给应用层,不要缓存 |
| 80 → 1896 | [ACK] Seq=1 Ack=80 Win=27136 Len=0 | 服务端确认:已收到 1+79=80 字节 |
| 80 → 1896 | [PSH,ACK] Seq=1 Ack=80 Len=230 | 服务端推送 HTTP 200 OK + JSON 响应,载荷 230 字节 |
| 1896 → 80 | [ACK] Seq=80 Ack=487 Win=65024 Len=0 | 客户端确认收到服务端响应数据 |
✅ HTTP 一问一答交互完成。
三、TCP 挥手断开连接(客户端主动关闭)
教材标准是四次挥手;真实网络中,服务端的 ACK 和 FIN 经常合并成一个报文,抓包只看到 3 个包属于正常优化,考试答题仍写四次挥手。
| 1896 → 80 | [FIN,ACK] Seq=80 Ack=487 Win=65024 Len=0 | 客户端告知:我方无数据发送,请求关闭【客户端→服务端】方向 |
| 80 → 1896 | [FIN,ACK] Seq=487 Ack=81 Win=27136 Len=0 | 服务端:确认客户端 FIN(Ack=80+1=81);同时我方也无数据,关闭【服务端→客户端】方向 |
| 1896 → 80 | [ACK] Seq=81 Ack=488 Win=65024 Len=0 | 客户端确认收到服务端 FIN(Ack=487+1=488) |
✅ 双向连接全部释放。
四、字段释义
| Win | 滑动窗口大小,流量控制,告诉对方当前本机最多可接收字节数 |
| MSS=1460 | 最大分段大小;TCP 单段最大载荷,MTU(1500) – IP头(20) – TCP头(20) |
| WS=256 | Window Scale 窗口缩放因子,用于高速网络放大窗口 |
| SACK_PERM | 允许选择性确认,丢包时只重传丢失分片,不用重传全部 |
| Len | TCP 载荷长度(不含 TCP 头部);Len=0 代表纯 TCP 控制报文,无应用层数据 |
五、序号校验示例
TCP 状态机
| LISTEN | 服务端 listen() 之后 | 等待 SYN |
| SYN_SENT | 客户端发 SYN 之后 | 等待 SYN+ACK |
| SYN_RCVD | 服务端收到 SYN、回了 SYN+ACK | 半连接队列在这里堆积 → SYN Flood 打的就是它 |
| ESTABLISHED | 双方都收到 ACK | 数据可传 |
| FIN_WAIT_1/2 | 主动关闭方发 FIN 之后 | |
| CLOSE_WAIT | 被动关闭方收到 FIN | 大量 CLOSE_WAIT = 应用没调 close(),代码问题 |
| TIME_WAIT | 主动关闭方最后 | 等 2MSL,保证最后一个 ACK 能重传、老报文自然消亡 |
| LAST_ACK | 被动关闭方发完 FIN |
排障口诀:TIME_WAIT 多 = 连接被主动关闭得太多,端口可能不够用;CLOSE_WAIT 多 = 应用没关连接,是 bug;SYN_RCVD 多 = 有人在打 SYN Flood。
流量控制 vs 拥塞控制(一句话区分)
| 解决谁的问题 | 接收方来不及处理 | 网络承受不住 |
| 手段 | 滑动窗口(Win) | 慢启动、拥塞避免、快重传、快恢复(CUBIC / BBR) |
| 信号 | 接收方通告窗口 | 丢包 / 时延 |
缺陷
利用
防御:SYN Cookie、SYN 队列调大 + 首包丢弃、防火墙/清洗设备、随机强初始序列号(现代 OS 用加密随机 ISN)、连接跟踪、限制单 IP 并发。
4.2 UDP(User Datagram Protocol,用户数据报协议)
这一节是原笔记缺失的部分,也是「为什么 DDoS 反射放大几乎都走 UDP」的答案所在。
4.2.1 是什么
| 名称 | UDP,User Datagram Protocol,用户数据报协议 |
| 层级 | 传输层;IP 协议号 17 |
| 核心作用 | 提供最小的传输服务:端口复用/分用 + 一个可选的校验和。不做连接、不做可靠、不做流控、不做拥塞控制 |
| 数据单位 | 数据报(datagram),一次发送一条,保留报文边界 |
| 一句话 | TCP 保证「字节流完整送到」;UDP 只保证「把这个数据报贴好端口号扔出去」,剩下的全交给应用层 |
它的设计哲学:把 IP 的能力几乎原样交给应用,只补两件事 —— 端口(进程寻址)和校验和(最基本的差错检测)。所以 UDP 的所有「缺点」,本质都是「故意不做」。
4.2.2 报文结构

首部只有 8 字节,4 个字段:
| 源端口 | 2B | 发送方端口 | 不需要回包时可以填 0 |
| 目的端口 | 2B | 接收方端口 | 交付给哪个进程 |
| 长度 | 2B | 首部 + 数据的总长 | 最小 8;16 位 → 单个数据报最大 65535 − 8 = 65527B |
| 校验和 | 2B | 覆盖伪首部 + 首部 + 数据 | IPv4 下可填 0 表示「不校验」;IPv6 下强制 |
对比一下就知道差距:
| 长度 | 20~60B | 固定 8B |
| 字段数 | 10+ | 4 |
| 有没有序号/确认号/窗口 | 有 | 一个都没有 |
4.2.3 校验和与伪首部
UDP 校验和的计算范围是:
伪首部(12B) + UDP 首部(8B) + UDP 数据
伪首部 = 源 IP(4B) + 目的 IP(4B) + 全 0(1B) + 协议号 17(1B) + UDP 长度(2B)
伪首部不真的发到线路上,只在计算校验和时临时拼出来。为什么要这么麻烦?因为要把 IP 层的源/目的地址也拉进校验 —— 否则一个包被错误投递(NAT 改写地址后没重算校验和)也检测不出来。
三个必须知道的点:
4.2.4 「8 字节首部」意味着什么
| 首部只有 8B | 小包开销极低(DNS 40B 的包里首部只占 20%) | 没有序号/确认号,做不到可靠传输 |
| 保留报文边界 | 一次 sendto 对应一次 recvfrom,接收方拿到完整一条 | TCP 的「粘包」问题在 UDP 里不存在(这题常考) |
| 无连接 | 无握手,省 1 个 RTT;服务端无状态,DNS 单机可扛极高 QPS | 源 IP 伪造零成本 → 反射放大的首选载体 |
| 无序、无重传、无流控 | 协议栈实现简单,时延低(语音/游戏) | 丢包、乱序、重复全上抛给应用层自己处理 |
| 无拥塞控制 | 应用可以按自己节奏发 | UDP Flood 只需无脑发包,不用管网络是否拥塞 |
| 超过 MTU 由 IP 分片 | 单条数据报可以很大 | 丢一个分片,整条数据报全废,且应用层不会自动重传 |

第 1 片 off=0 带 More fragments,第 2 片 off=185(185×8 = 1480 字节偏移)收尾;点开第 2 片看 UDP 长度字段写的是 Length: 2008,可这一帧只有 562 字节 —— 差的那 1480 字节在第 1 片里。中间丢任何一片,接收端都拼不出这条数据报,而 UDP 自己不会重传,只能靠应用层超时重发。
4.2.5 UDP 抓包:一次 DNS 查询
想看 UDP,最方便的例子就是 DNS。一条命令就够:
nslookup example.com # 触发一次 UDP 53 查询
Wireshark 过滤器:
udp.port == 53
抓到的应该是这样两个包(一往一返,没有任何握手和确认):
| 1 | 客户端:随机高位端口 → DNS:53 | DNS | Transaction ID = 0x8f3a,Queries = 1,A? example.com | 只有 8B UDP 头 + 一个 DNS 查询 |
| 2 | DNS:53 → 客户端:随机高位端口 | DNS | 同 Transaction ID,Answers = 1,A 93.184.216.34 | 端口对调,ID 必须一致才算「这是对刚才那个查询的回答」 |

上图左半是 4.1 节那条 HTTP 连接的完整过程(握手 3 包 + 数据 2 包 + 挥手 3 包),右半是这条 DNS 查询 —— 总共就 2 个包,问和答,完了。这就是「无连接」最直观的样子。
再补一张真正抓下来的(本机 10.41.231.117,校园网 DNS 10.41.231.140:53,nslookup www.hust.edu.cn):

第 3 条是查询、第 4 条是响应,时间差只有 0.7 ms;下方面板把 UDP 首部 4 个字段和 DNS 头都展开了,和 4.2.2 的结构图一一对应:
| UDP | Src Port: 55884 / Dst Port: 53 | 源端口(客户端随机高位端口)、目的端口(DNS 服务) |
| UDP | Length: 41 | 首部 8B + 载荷 33B = 41 |
| UDP | Checksum: 0x9820 [unverified] | 校验和;unverified 是网卡「校验和卸载」导致,不是抓包出错 |
| DNS | Transaction ID: 0x0002 | 请求与响应靠它配对 |
| DNS | Flags: 0x0100 Standard query | QR=0 查询,RD=1 希望递归 |
| DNS | Questions: 1 / Answer RRs: 0 | 查询报文没有回答段 |
| DNS | www.hust.edu.cn: type A, class IN | 问的是 A 记录 |
| DNS | [Response In: 4] | Wireshark 自动关联到第 4 条:A 202.114.0.245,91 字节 |
三个值得注意的点:① 整条交互只有 2 个包,没有建立/确认/释放;② 响应比请求大(91B vs 75B),这个比例到了反射放大里会被放大到成千上万倍;③ 列表里第 1~24 条都是同一时段的其它 DNS 查询,只有第 3、4 条是这次 nslookup。
4.2.6 跑在 UDP 上的常见协议
| 53 | DNS(主)/ mDNS 5353 | 一问一答、报文小、要求快;超 512B 或区域传送才走 TCP |
| 67 / 68 | DHCP(服务端 / 客户端) | 客户端此时还没有 IP,只能广播,无法建 TCP 连接 |
| 69 | TFTP | 极简实现(交换机刷固件) |
| 123 | NTP | 时间同步要求低时延,一次往返就够 |
| 161 / 162 | SNMP / SNMP Trap | 轮询式管理,简单 |
| 500 / 4500 | IKE / IPsec NAT-T | 隧道协商 |
| 3478 / 5349 | STUN / TURN | NAT 穿透,打洞必须 UDP |
| 1900 / 5353 | SSDP / mDNS | 局域网服务发现,靠组播 |
| 5060 | SIP | 语音信令,重传自己实现 |
| 443 | QUIC(HTTP/3) | 在用户态自己实现可靠传输,绕开 TCP 队头阻塞 |
| 11211 | memcached | 缓存查询;公网暴露就是灾难级放大器 |
4.2.7 缺陷
4.2.8 利用
① UDP Flood(直接洪泛)
伪造源 IP 向目标的大量端口发送 UDP 包 → 目标主机要么处理,要么回 ICMP 端口不可达(这又消耗一份资源)→ 带宽和 pps 被打满。
变种 Fraggle:把 UDP 包发到广播地址的 echo(7) / chargen(19) 端口,整个子网的主机都回包 → 1 个包变 N 个(和 ICMP 的 Smurf 是同一个思路)。
② 反射放大(Reflection & Amplification)—— UDP 最危险的用法
三步链条:
① 攻击者伪造源 IP = 受害者地址
② 向大量「开放服务」发送小请求(这些服务的响应很大)
③ 所有响应都打到受害者身上 → 放大倍数 = 响应大小 / 请求大小
| memcached | 11211 | 数千到数万倍 | 最猛,2018 年 GitHub 1.35 Tbps 攻击就是它 |
| NTP(monlist) | 123 | 数百倍 | 老版本 NTP 的 monlist 会返回最近 600 个客户端 |
| CLDAP | 389 | 数十倍 | LDAP 的 UDP 版 |
| DNS | 53 | 数十倍 | 需要开放递归解析器;ANY 查询、DNSSEC 响应更大 |
| SSDP | 1900 | 数十倍 | UPnP 设备发现 |
| SNMP | 161 | 数倍~数十倍 | 默认口令 public 就能查大量信息 |
| Chargen | 19 | 数百倍 | 每包回随机字符流 |
⚠️ 上表的倍数随配置、响应内容、请求构造变化很大,写论文/答题时应表述为「量级」而非精确值。
为什么必须是 UDP? 因为 TCP 要三次握手 —— 伪造源 IP 就收不到 SYN+ACK,连接根本建不起来,无法形成放大。UDP 无连接,一个包就能触发一个大响应。 这一句是这类题的标准答案。
③ UDP 分片攻击
- 构造总长 > 65535 或分片偏移重叠的 UDP 包,打老系统重组逻辑(Teardrop 的 UDP 版本);
- 把攻击载荷拆到多个分片,让只做逐包匹配的 IDS 漏检。
④ UDP 隧道 / 数据渗出
把其他协议封装进 UDP 载荷(DNS over UDP 53、NTP、甚至 53 端口跑自定义协议),穿出防火墙。因为「53 端口必须放行」是很多内网的做法。
⑤ UDP 扫描
UDP 没有握手,扫描器发一个空包,等 ICMP 端口不可达(Type 3 Code 3):收到 → 端口关闭;没收到 → 端口可能开着(也可能被防火墙静默丢弃,所以 UDP 扫描又慢又不准,nmap -sU 需要重试)。
⑥ QUIC 带来的新问题
HTTP/3 跑在 UDP 443 上,载荷全程 TLS 1.3 加密,中间设备看不到 SNI 之外的任何东西,传统基于 TCP 明文特征的 IDS 直接失效 → 只能靠流量行为特征(包长分布、时序)识别。这和你做流量分类是直接相关的点。
4.2.9 防御
| 根治 | 入口过滤(BCP 38 / uRPF):运营商侧丢弃源 IP 不属于本网段的包 → 从源头消灭伪造源 IP |
| 服务侧 | 关闭公网暴露的开放递归 DNS、NTP monlist、memcached、SNMP 默认口令 |
| 网络侧 | 每源 IP 的 pps/带宽限速、ANY 查询限流、分片策略(丢弃异常/微小分片) |
| 应用侧 | DNSSEC(防投毒)、DoH/DoT(加密)、QUIC 自带 TLS 1.3 |
| 监测 | 入向大包突增、单一目的端口 pps 突增、响应包 >> 请求包的流量模式 |
一句话:UDP 的防御重点不在「协议内部」(它什么都没有),而在边界过滤 + 服务配置 + 速率限制。
4.2.10 TCP 与 UDP 逐项对比
| 连接 | 三次握手 / 四次挥手 | 无连接 |
| 可靠性 | 确认 + 超时重传 | 无 |
| 顺序 | 有序,乱序重排 | 无 |
| 数据边界 | 字节流(有粘包问题) | 保留报文边界 |
| 首部开销 | 20~60B | 8B |
| 流量控制 | 滑动窗口 | 无 |
| 拥塞控制 | 慢启动 / CUBIC / BBR | 无(QUIC 在用户态自己实现) |
| 传输方式 | 点对点(不支持广播/组播) | 支持广播、组播 |
| 建连开销 | 1 个 RTT | 0 |
| 典型应用 | HTTP/1.1、SSH、SMTP、FTP | DNS、DHCP、NTP、语音、游戏、QUIC |
| 主要攻击 | SYN Flood、会话劫持、RST 注入 | UDP Flood、反射放大、分片攻击 |
| 一句话比喻 | 打电话:先接通,确认对方在听 | 寄明信片:写好就投,丢不丢不管 |
4.2.11 为什么 DNS 用 UDP、HTTP 用 TCP
| 单次数据量 | 小(通常 < 512B) | 大(页面、图片、JSON) |
| 交互模式 | 一问一答就结束 | 长连接、连续多轮 |
| 能否容忍丢包 | 能(超时重发一次即可) | 不能(内容必须完整) |
| 延迟敏感度 | 极高(每次上网第一步,多 1 RTT 就很明显) | 相对低 |
| 结论 | UDP 为主,必要时降级到 TCP | TCP 为主 |
DNS 的「必要时走 TCP」有三个触发条件,考试常考:
下一篇:应用层与安全视角
《网络协议安全笔记(下):应用层与安全视角》接着讲:
- HTTP / DNS / TLS / HTTPS / DHCP / SSH 的报文结构与原生缺陷(TLS 的 SNI 为什么是明文、DNS 投毒怎么发生、伪造 DHCP 服务器为什么能一次劫持整个网段)
- 一张「攻击面总表」,把 10 个协议的缺陷、典型攻击、防御对上号
- 「明文与密文边界」:普通链路 / HTTPS / IPSec 隧道 / GRE 隧道 四种情况,链路上到底谁看得见什么
- 「抓包排错清单」:看到 Retransmission、Port unreachable、Fragmented IP protocol 分别说明什么问题,以及每张图的复现命令
网硕互联帮助中心

评论前必须登录!
注册