WireGuard 是一个运行在 UDP 之上的点对点隧道协议,2020 年起进入 Linux 主线内核(5.6)。它的特点不在功能多,而在能做的事被刻意限制得很少:没有算法协商,没有证书体系,也没有会话状态机里的各种分支。读懂它只需要弄清三件事:怎么握手,怎么路由,怎么换密钥。
握手:一次往返建立会话密钥
WireGuard 的握手基于 Noise 协议框架中的 Noise_IK 模式。双方各持有一对 Curve25519 密钥,对方的公钥需要事先通过带外方式拿到。发起方知道响应方的公钥,所以第一个握手包里就能携带自己的静态公钥和临时公钥,响应方回复自己的临时公钥后,双方各自派生出会话密钥。整个过程只需要一个来回。

握手用到了哪些密码原语
密钥交换使用 Curve25519,数据加密与认证使用 ChaCha20-Poly1305,哈希使用 BLAKE2s,密钥派生使用 HKDF。这套组合是写死在协议里的,没有协商环节,也就没有降级攻击可以利用的缝隙。想升级算法,只能整体换协议版本。
为什么陌生的数据包得不到任何回应
握手初始包里带有一个由响应方公钥派生的 MAC。拿不到响应方公钥的人发来的包会在这一步被直接丢弃,服务端不回复任何内容。扫描器因此看不到一个会应答的端口,这也是 WireGuard 常被描述为“静默”的原因。
Cryptokey 路由:公钥就是身份,AllowedIPs 就是路由表
每个对端(peer)在配置里由公钥标识,并带一个 AllowedIPs 列表。这个列表同时承担两个角色:发包时,内核按目标地址在各 peer 的 AllowedIPs 里做最长前缀匹配,决定用哪个 peer 的密钥加密;收包时,解密成功后检查内层源地址是否落在该 peer 的 AllowedIPs 内,不在就丢弃。
[Interface]
PrivateKey = <本机私钥>
Address = 10.8.0.2/32
[Peer]
PublicKey = <对端公钥>
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25这段配置里,10.8.0.0/24 的流量会进入隧道,其余流量走原有路由。把 AllowedIPs 写成 0.0.0.0/0 才表示全部流量走隧道。

漫游时端点地址如何更新
WireGuard 不绑定对端的 IP 地址。只要收到一个能通过认证的数据包,就把它的来源地址记为该 peer 当前的 Endpoint。手机从 Wi-Fi 切到蜂窝网络,隧道不需要重新握手就能继续工作,下一个包自然带着新地址。
密钥轮换与保活
一个会话的数据密钥使用约 2 分钟后,发送方在下一次有数据要发时发起新的握手;超过约 3 分钟没有更新的会话密钥会被拒绝使用。没有流量时,WireGuard 既不握手也不发包,链路上完全安静。
什么时候需要 PersistentKeepalive
位于 NAT 之后又需要被主动访问的一端,要设置 PersistentKeepalive,常见取值是 25 秒,用来让 NAT 设备保留映射表项。只做出站访问的客户端通常不需要它,设置后会多出少量周期性流量。
与其他方案的设计差异
| 维度 | WireGuard | OpenVPN | IPsec/IKEv2 |
|---|---|---|---|
| 传输层 | 仅 UDP | UDP 或 TCP | ESP / UDP 4500 |
| 算法选择 | 固定套件,无协商 | 可协商 | 可协商 |
| 身份认证 | 公钥 | 证书或用户名密码 | 证书、预共享密钥等 |
| 配置复杂度 | 较低 | 中等 | 较高 |
固定算法意味着实现更小、审计更容易,代价是灵活性:需要用户名密码、证书吊销、动态地址池这类能力时,要在 WireGuard 之外自己补管理层。
常见问题
WireGuard 能走 TCP 吗
协议本身只用 UDP。需要穿过只放行 TCP 的网络时,要在外面再套一层隧道,这会带来 TCP over TCP 的重传叠加问题,应当作为最后手段。
公钥泄露会有什么后果
公钥本来就是公开的,泄露不影响安全。真正需要保护的是私钥,一旦私钥泄露,应立即在对端移除旧公钥并重新生成密钥对。
为什么两端时间不同步也能正常握手
握手使用 TAI64N 时间戳防重放,要求新握手的时间戳大于上一次,而不是与对方时钟对齐。设备时间大幅回拨才会导致握手被拒。
