Files
cs-note/hhs/NETWORK/10-前沿与进阶/03-WireGuardVPN原理与实践.md
T
2026-05-24 11:42:38 +08:00

6.8 KiB

tags, create time
tags create time
计算机网络
WireGuard
VPN
ChaCha20
Curve25519
OpenVPN
IPsec
2026-05-18 05:35

WireGuard VPN 原理与实践

概述

WireGuard 是一个极简的 VPN 协议,代码量不到 OpenVPN 的 1/10、IPsec 的 1/25。它凭借极低的延迟和超高的吞吐量,正在成为新一代标准 VPN 方案——甚至已合入 Linux 内核(≥ 5.6)。

为什么比 OpenVPN / IPsec 快?

flowchart LR
    IPsec["IPsec\n• IKEv2 密钥交换 (多轮 RTT)\n• ESP/AH 扩展头链\n• 用户态+内核态来回跳转\n• ~10-20 种 cipher suite 协商"]
    
    WG["WireGuard\n• Curve25519 密钥交换 (单次)\n• ChaCha20-Poly1305 AEAD\n• 纯内核态实现 (netlink API)\n• 仅 4 种密码学原语"]
    
    style IPsec fill:#DDA0DD,color:#000
    style WG fill:#98FB98,color:#000

性能对比实测数据

指标 WireGuard OpenVPN (UDP) IPsec
吞吐量 ~9.5 Gbps ~1.5 Gbps ~3.0 Gbps
CPU 占用 (Gbps) 0.8% 12.5% 3.2%
握手延迟 < 1ms 50-200ms 100-300ms
代码行数 ~4,000 LoC ~50,000 LoC ~100,000 LoC
配置复杂度 极简 (INI 格式) 中等 复杂
NAT 遍历 原生支持 需要辅助 (UDP encapsulation) 复杂
移动性 支持 (PersistentKeepalive + endpoint change) 部分支持 有限支持

[!tip] 代码行数少 = 更少的 bug = 更高的安全性

审计 ~4000 行 C 代码的成本远低于审计 ~50000 行。而且每少一行代码就少一个潜在的漏洞入口。

WireGuard 的密码学基础

WireGuard 仅使用 4 种经过严格审查的密码学原语:
───────────────────────────────────────────────
1. Curve25519        — ECDH 密钥交换 (x25519)
2. ChaCha20          — 对称加密 (AES 替代)
3. Poly1305          — MAC / AEAD 认证
4. SHA-512           — 哈希函数

没有: RSA, ECC(除Curve25519外), CBC, HMAC, DRBG...
→ 选择极少 → 无协商 → 更快更简单

三重加密手风琴 (Triple Handshake)

sequenceDiagram
    participant A as Peer A
    participant B as Peer B
    
    Note over A,B: 1. A → B: 主动握手 (A 发起)
    A->>B: {Ephemeral Key A} 用 B's Static Key 加密
    B->>A: {Ephemeral Key B} 用 A's Ephemeral Key + B's Static Key 加密
    A->>B: {Empty} 用 A's Ephemeral Key + B's Ephemeral Key 加密
    Note over A,B: ✅ 三方加密完成, 会话密钥建立
    
    Note over A,B: 2. B → A: 响应式重握手 (B 轮换密钥)
    B->>A: {Ephemeral Key B'} 用 A's Static Key 加密
    A->>B: {Ephemeral Key A'} 用 B's Ephemeral Key + A's Static Key 加密
    B->>A: {Empty} 用 B's Ephemeral Key + A's Ephemeral Key 加密
    Note over A,B: ✅ 新会话密钥, 前向保密保证

[!question] 什么是前向保密 (Forward Secrecy)? 即使长期密钥(Static Key)未来被泄露,也无法解密过去的通信——因为每次会话都使用了临时的 Ephemeral Key。三重手风琴保证了每一轮的临时密钥都在下一轮中被"销毁"。

WireGuard 配置详解

server.conf

[Interface]
Address = 10.0.0.1/24              # WireGuard 虚拟网卡 IP
ListenPort = 51820                  # UDP 监听端口
PrivateKey = <server_private_key>   # 私钥 (安全保存!)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE  # NAT 转发
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]                              # 客户端 1
PublicKey = <client1_public_key>
AllowedIPs = 10.0.0.2/32           # 只允许这个 IP 通过这个 peer
PersistentKeepalive = 25           # 每 25s 发一次 keepalive (穿透 NAT)

[Peer]                              # 客户端 2
PublicKey = <client2_public_key>
AllowedIPs = 10.0.0.3/32
PersistentKeepalive = 25

client.conf

[Interface]
Address = 10.0.0.2/24              # 客户端自己的虚拟 IP
PrivateKey = <client_private_key>   # 客户端私钥

# DNS 解析通过隧道走 VPN
DNS = 10.0.0.1

[Peer]
PublicKey = <server_public_key>     # ⚠️ 注意方向: 客户端存服务端的公钥
Endpoint = vpn.example.com:51820   # 服务器地址
AllowedIPs = 0.0.0.0/0             # 所有流量走 VPN (全隧模式)
# AllowedIPs = 10.0.0.0/24       # 仅内网流量走 VPN (-split tunneling)
PersistentKeepalive = 25

一键生成密钥对

# 生成服务器密钥对
$ wg genkey | tee server-private.key | wg pubkey > server-public.key

# 生成客户端密钥对 (可重复 N 次)
$ wg genkey | tee client1-private.key | wg pubkey > client1-public.key
$ wg genkey | tee client2-private.key | wg pubkey > client2-public.key

# 生成 QR Code (方便手机扫码连接)
$ qrencode -t UTF8 <(cat <(echo "[Interface]"); echo "PrivateKey=$(cat client1-private.key)"; echo "[Peer]"; echo "PublicKey=$(cat server-public.key)"; echo "AllowedIPs=0.0.0.0/0"; echo "Endpoint=vpn.example.com:51820"; echo "PersistentKeepalive=25")

日常运维命令

# 启动 WireGuard
$ sudo wg-quick up wg0
$ sudo systemctl enable --now wg-quick@wg0   # 开机自启

# 查看状态
$ wg show
interface: wg0
  public key: abc123def456...
  private key: (hidden)
  listening port: 51820

peer: xyz789ghi012...
  endpoint: 203.0.113.5:45678
  allowed ips: 10.0.0.2/32
  latest handshake: 3 seconds ago         ← 3 秒前还在握手! 连接活跃
  transfer: 1.23 GiB received, 890 MiB sent

# 动态添加/移除 peer (不需要重启!)
$ wg set wg0 peer <new_pubkey> allowed-ips 10.0.0.4/32
$ wg remove wg0 peer <old_pubkey>

# 导入导出配置
$ wg syncconf wg0 <(wg-quick strip wg0)

WireGuard 的限制与注意事项

⚠️ WireGuard 不适合的场景:
─────────────────────────────────
• 需要传统用户认证 (PAP/CHAP/LDAP) → WireGuard 只认密钥
• 细粒度 per-user 带宽控制 → 需配合 tc (traffic control)
• 大规模动态节点 (千级以上) → 管理 1000 个 peer 的 AllowedIPs 很痛苦
• 与现有 IPsec 设备互通 → WireGuard 不能做 IPsec gateway

✅ WireGuard 非常适合:
─────────────────────────────────
• 个人/小团队私有 VPN
• 云服务器到 IDC 的专线
• IoT 设备远程管理
• Kubernetes 集群跨 AZ 通信

关联笔记