IPsec and VPN

Sources:

  1. Computer Networking: A Top-Down Approach

本文介绍了常见的网络层安全协议 IPsec。通过对它的学习,可以理解计算机网络中许多安全协议的基本设计思想;此外,你还可以掌握 VPN 的核心概念。

Network-Layer Security: IPsec and Virtual Private Networks'tags: Computer Networking

前置知识

在阅读本文之前,你需要对计算机网络有基本了解,尤其是网络层(Network layer)和 IP 协议的基本概念。推荐阅读:

  1. 计算机网络概论
  2. 计算机网络的网络层

此外,本文约定如下术语:

  1. 在网络层通信中,我们将参与通信的节点称为实体(entity)。在实际系统中,实体通常指主机或路由器上的网络协议栈(network stack),而不是单独的网卡(network interface)。 需要注意的是,在网络拓扑图中,我们通常用“主机”或“路由器”来表示这些实体,而这些设备上的网络接口(网卡)则是数据报进出的具体位置。
  2. 网络拓扑视角来看,连接两个不同网络(例如局域网与 Internet)的路由器称为边界路由器(border router);从主机视角来看,当目标地址不在本地子网时,主机会将数据包发送给一个预先配置的下一跳设备,这个设备称为网关(gateway),通常也称为默认网关(default gateway)。在简单的网络中,这两者通常是同一个设备(例如家庭路由器);但在更复杂的网络中,主机的默认网关不一定是实际连接外部网络的边界路由器。

引言

考虑这样一个公司网络。公司拥有一个总部网络(Headquarters)和一个分部网络(Branch Office),同时还有一些经常在外出差的员工,这些员工需要在酒店等外部环境中通过互联网访问公司内部资源。

由于总部、分部以及远程员工分别处于不同的局域网中,并且在地理上可能相距较远,因此它们之间的通信只能通过公共 Internet 完成。

然而,公司通常希望实现这样一种效果:

总部网络、分部网络以及远程员工之间的通信,应该像在一个私有网络中一样安全、可控。

这种在公共 Internet 上构建“逻辑私有网络”的技术,称为 VPN(Virtual Private Network)。我们把 VPN 的细节放在最后一节,目前只需要理解:

VPN 的目标是让不同的局域网在逻辑上看起来像连接在同一个局域网中。

在这一抽象下,公司网络可以表示为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
           Headquarters Network                  Branch Office Network
172.16.1.0/24 172.16.2.0/24

+------------------------+ +------------------------+
| Host | | Host |
| 172.16.1.17 | | 172.16.2.48 |
+------------------------+ +------------------------+
| ^
| |
+------------------------+ +------------------------+
| R1 (border router) |==================| R2 (border router) |
| | Public Internet| |
| LAN: 172.16.1.1 |==================| LAN: 172.16.2.1 |
| WAN: 203.0.113.1 | IPsec tunnel | WAN: 198.51.100.1 |
+------------------------+ +------------------------+
^
|
+------------------------+
| Laptop (remote) |
| (dynamic public IP) |
+------------------------+

其中,R1 和 R2 分别是两个局域网的边界路由器,也作为两个局域网的网关。

接下来,我们关注不同网络之间的通信。例如,总部中的主机 172.16.1.17 向分部中的主机 172.16.2.48 发送数据。

在默认情况下,这种通信依赖于 IP 协议。然而IP 协议本身并不提供任何安全性保证。普通 IP 数据报在 Internet 上传输时是明文的,中间节点可能:

  • 读取数据内容(缺乏机密性)
  • 篡改数据(缺乏完整性)
  • 冒充发送方(缺乏认证)
  • 重放旧数据包(缺乏防重放能力)

对于企业网络而言,这种通信模型显然是不可接受的。

因此,我们需要在 IP 层之上引入一套机制,为网络层的数据包(IP packet)提供安全性,从而实现 VPN 的目标。

常见的网络层安全协议包括 IPsec, WireGuard, ...出于教学与历史代表性的考虑,本文将重点介绍其中最经典的一种协议:IPsec (IP Security)。

此外,在本文最后,我们会看到 IPsec 实现了 VPN 的功能,因此 VPN 和 IPsec 在很多语境中是混用的。尽管现代 VPN 用的协议不一定是 IPsec,但一定和 IPsec 相似,因此我们把对 VPN 的介绍放在了最后一节,因为在学会 IPsec 后,你就自动学会了 VPN。

IPsec 是什么?

如前所述,IPsec(IP Security) 是工作在网络层的安全协议,用来保护 IP 数据包。具体来说,IPsec 不是一个协议,而是一组协议。其中最主要的两个协议为 AH(Authentication Header)和 Encapsulation Security Payload(ESP),而 ESP 由于功能更多而更多地被采用,因此我们只介绍 ESP 协议。

此外,IPsec 有两种模式:Transport mode 和 Tunnel mode,它们定义了不同格式的 IPsec 数据包。Tunnel model 就是我们在VPN中经常见到的 TUN mode(隧道模式)。它更通用,因此本文中只介绍 tunnel mode。

我们通常说的 IPsec 协议,在无特殊说明的情况下,指的就是 tunnel mode 的 ESP 协议。

为了实现网络层通信的安全性,IPsec 需要做到:

安全目标 普通 IP 是否提供? 含义
机密性(confidentiality) 其他人不能看到数据内容
完整性(integrity) 数据在传输过程中没有被篡改
发送方认证(sender authentication) 数据确实来自声称的发送方
防重放(anti-replay) 攻击者不能把旧的数据包重新发送一遍来冒充新请求

它的做法是:把原来的 IP 数据包封装起来,并对其中的内容进行加密、认证、防重放、完整性保护。

此外,一个 IPsec 数据包在格式上等同于一个 IP 数据包,这意味着 IPsec 协议对上层(传输层和应用层)是透明的,采用 IPsec 协议并不需要修改传输层和应用层。

Security Association

既然 IPsec 保证了机密性(confidentiality),那么它就一定要对数据进行加密,而无论是对称加密还是非对称加密算法,都需要通信的两个实体间共享密钥和使用的具体加密算法。

而为了保证完整性(integrity),IPsec 采用了常见的 MAC 算法。简单来说,假设实体 R1 向 R2 发送消息 \(m\),那么双方首先会共享一个密钥 \(s\), R1 先计算哈希值 \(H(m+s)\),这个值称为 MAC,然后将 \(m\)\(H(m+s)\) 一起发给 R2。B收到消息后,会使用 \(s\) 来自己计算 MAC,如果与收到的 \(H(m+s)\) 相同,那么就说明载荷 \(m\) 没有被篡改。

发送方认证(sender authentication)和防重放(anti-replay)也类似。

可以看到,这些安全目标全都需要通信双方实体(路由器或主机)事先知道一些共识信息,这一整组信息,就被组织为一个安全关联(Security Association,SA)。一个 SA 中通常会包含:

字段 作用
SPI(Security Parameter Index) SA 的编号,用来让接收方知道该用哪一个 SA 处理这个包
加密算法 例如使用哪种对称加密算法
加密密钥 用来加密和解密数据
认证算法 用来生成 MAC,检查数据是否被篡改
认证密钥 用来计算和验证 MAC
序列号 用于防止重放攻击
SA 生命周期 指定这个 SA 什么时候过期或需要更新

需要注意,IPsec 的 SA 是 单向的(unidirectional)。也就是说:

  • R1 到 R2 的通信需要一个 SA。
  • R2 到 R1 的通信需要另一个 SA。

并且 SA 也并不是一条真正的(无论是哪一层的)通信线路,而是一个事先的约定。

一个实体可以同时和很多实体建立 SA,而这些 SA 数据都存放在 OS 内核的一个叫做 Security Association Database (SAD) 的数据结构中。


IPsec 数据包的格式

在 tunnel mode + ESP 的情况下,一个 IPsec 数据报的格式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
							|<-------------------- authenticated ------------------------>|
|<---------------- encrypted -------------------->|

+------------+------------+------------+-----------------------+------------+---------+
| New IP hdr | ESP header | Orig IP hdr| Original IP payload | ESP trailer| ESP MAC |
+------------+------------+------------+-----------------------+------------+---------+
|<---------->| |<---------->|
| | +---+------------+---+
| | | |
v v v v
+---------+--------+ +---------+---------+----------+
| SPI | Seq # | | Padding | Pad len | Next hdr |
+---------+--------+ +---------+---------+----------+
|<-- ESP header -->| |<------ ESP trailer ------>|

可以看到,ESP 数据包在格式上依然是个 IP 数据包,它把原有的 IP 数据包作为 payload 打包进去,并且加上了新的 IP header,其中的源地址和目的地址也被换成了通信双方所属网络的边界路由器的地址,即

1
2
3
New IP header:
src = 本端网关(如 R1 的 203.0.113.1 )
dst = 对端网关(如 R2 的 198.51.100.1 )

而原始通信双方的地址(例如 172.16.1.1 → 172.16.2.1)则被封装并隐藏在加密部分中。

ESP header

ESP header 中包含两个关键字段:

  • SPI(Security Parameter Index):用于标识该数据报所属的 SA。由于接受方可能同时和很多实体建立了 SA,因此需要通过 SPI 来在 SAD 中查找对应的 SA。
  • Sequence Number:用于防止重放攻击。接收方会检查该字段是否在允许的窗口内,以判断该数据报是否为旧包的重放。

其余注意事项

  1. 原始 IP 数据包,连同一个 ESP trailer 会被加密。对前者加密很好理解,但为什么我们还需要一个 ESP trailer 并且对它也加密呢?原因是 IPsec 使用的加密算法为块加密(block cypher),要求加密数据长度必须是某个正整数的整数倍。而为了达到这个长度要求,我们需要对数据做填充(padding),同时需要 Pad Length 来记录填充长度;而 Next Header 用于标识原始 IP 数据包中 payload 的类型(例如 TCP / UDP / IPv4 等)。
  2. 载荷中包括 ESP header, 原始 IP 数据包,ESP MAC 和 ESP trailer。原始 IP 数据包自自不必谈,ESP header 用于实现 ESP 协议,因此是必须的;而 ESP MAC 则用于数据的完整性校验,也是必须的;ESP trailer 是为了满足加密算法的要求,也是必须的。
  3. ESP header 不需要加密,但会参与认证。如前所述,接收方必须先读取 ESP header 中的 SPI,才能确定使用哪个 SA 来解密后续内容。如果 ESP header 也被加密,那么接收方在不知道 SA 的情况下就无法解密该数据包。
  4. 一般来说,新数据包的 IP header 里的协议号是 50,表明这是个 IPsec 数据包。不过,我们完全可以修改这个协议号为 TCP UDP的协议号,让这个数据包无法被互联网区分(即认为它就是个普通 IP 数据包)。

知道了IPsec 数据包的格式,通信实体如何创建或者解析它也就很显然了,因此我们不在此展开。


IPsec 的实现细节

哪些数据包需要 IPsec?

假设我的手机通过 IPsec 连接到公司的内部网络。那么,当我访问公司内网服务时,这些数据包显然需要通过 IPsec 进行封装和保护。然而,我的手机同时也会访问公网,例如浏览网页、看视频、打游戏或收发邮件。这些流量的目的地是 Internet,本身已经可以通过普通 IP 通信完成,因此不应该经过 IPsec 封装。

这就引出了一个关键问题:

对于一个即将发送的 IP 数据包,系统如何判断它是否需要使用 IPsec?

需要注意的是,在发送数据包时,我们处在 IP 层,此时:

  • 数据包还没有被封装成 IPsec 数据报;
  • 因此也还没有 ESP header;
  • 更没有 SPI(Security Parameter Index)。

换句话说:

在发送阶段,我们无法通过 SPI 来判断这个数据包是否属于某个 SA。

因此,系统必须依赖一组基于数据包属性的匹配规则来决定每个数据包应该如何处理。这些规则通常类似于:

1
2
3
4
5
6
7
8
if (src in 172.16.1.0/24 AND dst in 172.16.2.0/24)
→ protect (use IPsec, e.g., ESP tunnel)

if (dst == 8.8.8.8)
→ bypass

if (dst in 某敏感网段 AND 不允许明文)
→ discard

这些规则并不是临时判断的,而是持久化存储在操作系统内核中的一个数据结构中,称为 Security Policy Database (SPD)。

因此,在发送路径中:

1
packet → SPD(决策) → SAD(选择 SA) → IPsec 封装

通过哪个网卡发送?

当一个数据包通过规则匹配而被判定属于某个 SA 后,操作系统就可以对其进行封装,生成 IPsec 数据包。然而,很多计算机有多个网卡(网络接口,network interface),而 IPsec 协议本身没有规定该发送到哪个网卡,后者是路由表决定的。

例如,我的电脑有如下网卡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether bc:d0:74:18:63:86
inet6 fe80::181d:259e:78aa:4346%en0 prefixlen 64 secured scopeid 0xe
inet 192.168.2.202 netmask 0xffffff00 broadcast 192.168.2.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active

utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
inet6 fe80::c128:5aa6:f76c:3234%utun0 prefixlen 64 scopeid 0x12
nd6 options=201<PERFORMNUD,DAD>

而我的路由表是:

1
2
3
4
5
6
7
8
9
10
11
$ netstat -rn -f inet
Routing tables

Internet:
Destination Gateway Flags Netif Expire
default 192.168.2.1 UGScg en0
127 127.0.0.1 UCS lo0
127.0.0.1 127.0.0.1 UH lo0
169.254 link#14 UCS en0 !
192.168.2 link#14 UCS en0 !
<snip>

可以看到,路由表定义了一个 IP 数据包应该由哪个网卡发送的规则。很多 VPN 软件会修改路由表,以确保需要转发的数据包都在路由表中被匹配到某个固定的网卡并发送。

IKE:如何建立 SA?

我们知道,IPsec 的安全性依赖于一组“安全参数”,包括使用的加密算法,共享的密钥等等,这些参数被组织在 Security Association(SA)中。

然而,SA 需要首先被建立。一个最直接的方法是由网络管理员在每个实体中预先写入这些安全参数。但在实际系统中,这种做法既难以扩展(节点数量多),也不安全(密钥需要周期性更新)。

而建立共识则需要另外一套流程。

你当然可以手动在所有实体(主机,路由器)里手动写好共识,但这种做法是不切实际的,因为实体太多了。此外,因为密钥需要定期更新,所以这种做法是不安全的。

IPsec 使用 IKE(Internet Key Exchange)协议来自动建立 SA。IKE 本身不是用于传输数据的,而更像是一个“前期谈判协议”,先让双方商量好安全参数。

IKE 协议的细节偏离本文重点,因此这里不再展开。


IKE:如何建立 SA?

在前文中我们提到,IPsec 的安全性依赖于一组安全参数,其中包括:

  • 使用的加密算法
  • 使用的认证算法
  • 对应的密钥材料
  • 以及相关的状态信息(如 sequence number 等)

然而,这些参数并不会凭空存在。通信双方必须首先就这些内容达成一致,并建立共享的密钥。这一过程本身就是一个独立的问题。

理论上,可以通过手动配置的方式,

VPN

有了 IPsec,我们才能在网络层进行安全地通信。这还额外导致了 VPN 技术的产生。所谓的 VPN,笼统地讲,就是让处于两个局域网的设备共同处于一个更大的逻辑上的局域网,这自然需要在两个局域网之间建立通信连接,而这种连接经常是跨地域的,因此需要途径互联网,因此就一定需要网络层安全协议。

实际上,使用 IPsec 就等于使用 VPN,因为 IPsec 保证了你可以从你的局域网安全地通过互联网向另一个局域网内部的设备发送消息,并且在你眼中,你和目的实体都处于同一个局域网内(使用同一个子网)。

不过,网络层的 IP 安全协议不止 IPsec,还有 wirehuard 等。因此 VPN 技术使用的不一定是 IPsec。不过,这些网络层安全协议都是相似的,因此只要理解了 IPsec,就可以不需要知道其他协议地理解绝大多数 VPN。

常见问题 FAQ

问:既然应用层已经有 HTTPS / SSH 这样的安全协议,为什么还需要 IPsec?用了 HTTPS 不就已经是“安全通信”了吗?

答:在分层模型中,每一层协议只负责保护该层及其上层的语义。因此应用层协议可以保证应用层数据的安全性,例如 HTTPS 可以保证 HTTP 数据(包括请求方法,URL,请求体等等)的安全性,但是它不会保护 IP 层及以下的信息,例如通信双方的 IP 地址,数据包的发送时间与频率等等。一个简单的类比:我和你在微信上交流,用 HTTPS 就好比我向你发送了一份加密文件,文件内容是安全的,但是通信双方的身份(我和你),聊天记录的时间,数量,都是可以被路过的人轻易看到的。


问:我知道有很多“VPN”(比如 Clash),它们也是基于 IPsec 这样的网络层安全协议吗?

答:VPN这个词现在已经被滥用了,我们经常把所有能翻墙的工具都叫做 VPN。但严格来说,只有像IPsec那样在网络层工作的才是 VPN;而 Clash 等工具工作在多个层,不是 VPN,而应该叫做“代理工具”。关于 Clash 等现在常用的 “VPN” 或者代理工具,请看我单独写的一篇笔记


问:IPsec 有多常用?

答:答案可能有些出人意料:IPsec(起码在中国)并不是最常用的网络层安全协议,虽然它的想法很经典,但是 IPsec 数据包的流量特征比较容易辨别,因此容易遭到分析和针对。不过,这不影响它在教学上的价值。对于计算机网络从业者之外的人来说,如果想了解网络层安全协议以及 VPN,了解 IPsec 就足够了。