把 WireGuard 理解成「更快的 OpenVPN」或「配置更简单的 IPSec」,会漏掉真正的设计主张。Jason A. Donenfeld 在 NDSS 2017 论文里写得很直白:Linux 上标准的加密隧道方案是 IPsec + xfrm + 用户态 IKEv2;分层在语义上正确,但正确分层把正确部署变成了几乎不可完成的任务。WireGuard 从「有缺陷的分层破坏」出发,再用密码学与系统手段把洞补上——这是哲学,不是实现细节。
本文只谈立场与公理。握手字段见 协议原理;内核路径见 代码篇。选型数字与 OpenVPN 对照见 VPN 工程对比。
一、问题从哪来:正确分层的代价
IPSec 把三件事拆开:
- 密钥交换(通常 IKEv2,RFC 7296 及大量扩展)
- 变换 / SA(内核 xfrm:SPD 选策略,SAD 绑密钥与算法)
- 接口与防火墙语义(与普通网卡规则不完全同构)
Donenfeld(NDSS 2017, §I)承认:密钥交换与传输加密分离、变换层与接口分离,在网络与安全教科书里都站得住。问题在工程:管理员要在多个命名空间里保持一致;防火墙对「经 IPsec 的包」有另一套标签;出了问题很难判断是 IKE、SPD 还是 SAD 哪一层与预期不一致。
OpenVPN 站在另一端:用户态 TUN/TAP + TLS。接口模型更接近普通网卡,但把 ASN.1/X.509 与庞大 TLS 状态机留在长期守护进程里;论文指出内核里塞 TLS/X.509 解析器历史上出过严重漏洞(文中举例 CVE-2008-1673、CVE-2016-2053),因此 OpenVPN 留在用户态是合理的——代价是多次内核–用户拷贝与「看起来很有状态」的运维面。
WireGuard 的目标陈述(论文 Abstract)可以压缩成一句话:用更少的代码、更固定的密码学、更接近普通网卡的管理面,替代多数场景下的 IPsec 与 OpenVPN。
二、公理一:安全隧道的基本原理是公钥 ↔︎ IP 绑定
论文 §II 提出 cryptokey routing:peer 的唯一身份是 32 字节 Curve25519 公钥;每个公钥绑定一组 Allowed IPs。
出方向:内层目的 IP → 查表选公钥 → 用该 peer
的会话密钥加密。
入方向:解密认证通过后,内层源 IP
必须仍落在同一公钥的 Allowed IPs
上,否则丢弃。
这不是「路由功能外挂了一个 VPN」,而是主张:安全隧道的基本不变量就是「谁可以用哪些源 IP」。SPD/SAD 的两层表在 WireGuard 里塌缩成一张表。代价也很清楚:它要求协议是纯 L3——没有「源 IP」的 L2 帧无法做同样的绑定,因此 WireGuard 拒绝做通用 L2 VPN(论文 §I、§II)。
flowchart LR
subgraph IPSec[IPSec Layering]
IKE[IKEv2 Daemon]
SPD[SPD]
SAD[SAD]
XFRM[xfrm Transform]
end
subgraph WG[WireGuard Model]
CK["Public Key + AllowedIPs"]
IF["wg0 net_device"]
end
IKE --> SPD --> SAD --> XFRM
CK --> IF
论文自己把这叫做对「学术完美分层」的背离,然后用 roaming、静默丢弃、cookie DoS 机制等补工程问题。读后续协议与代码时,应把 cryptokey routing 当成公理,而不是「配置语法糖」。
三、公理二:管理面看起来无状态
配置完成后,密钥交换、断线重连、endpoint
发现应对管理员透明:wg0 像一张普通网卡,用
ip(8)
配地址与路由,用普通防火墙规则约束从该接口进来的包——并保证这些包已经过认证加密(论文
§I)。
这推出几条工程推论:
- 不把「连接」暴露成必须显式 dial/hangup 的对象(对比许多 TLS VPN 客户端)。
- 握手失败对扫描者尽量不可见:未认证包不分配状态、默认不响应(§V-A “Silence is a Virtue”)。
- NAT 穿越靠固定 listen port + endpoint 学习,而不是另起一套信令(§II-A)。
「无状态」是对外观的描述,不是实现里没有状态机。内核里有 timer、keypair 轮换与队列;哲学要求是这些状态不进入管理员的日常心智模型。
四、公理三:密钥分发不在这一层解决
WireGuard 的静态公钥交换刻意学 OpenSSH:带外完成,协议不绑定 X.509、CRL、OCSP(论文 §I)。公钥 32 字节、Base64 约 44 字符,方便邮件、配置管理、密钥分发系统投递。
这不是「没有身份」,而是身份 = 公钥,信任锚放在运维流程里。合规若强制要求证书链与撤销基础设施,哲学上就不匹配——应回到 IKEv2 或在 WireGuard 之外另建身份平面(见 深度篇 与零信任系列)。
可选预共享对称密钥(PSK)也不改变这条公理:PSK 是对 ECDH 的额外混合,用于「极偏执」的量子威胁模型(§V-B),不是 PKI。
五、公理四:密码学观点(cryptographically opinionated)
论文 §I 写明:WireGuard 故意没有 cipher 与协议敏捷性。原语固定为:
| 角色 | 选择 | 规范锚点 |
|---|---|---|
| ECDH | Curve25519 | Bernstein |
| AEAD | ChaCha20-Poly1305 | RFC 7539 |
| Hash / KDF | BLAKE2s + HKDF | RFC 7693 / RFC 5869 |
| 握手框架 | Noise IK(及 PSK 变体) | Noise Protocol Framework |
立场是:TLS 历史上大量漏洞与「可协商」相关;与其保留降级与组合爆炸,不如原语出洞时全员升级协议版本。netdev 邮件列表里对「失败日怎么办」的争论,以及「用 message type / 版本严格演进」的回应,放到 深度篇。
握手模式选 Noise IK:发起方预先知道响应方静态公钥——这与 VPN「配好对端公钥再通信」的运维模型同构,也与「第一条消息即可认证、尽量不分配未认证状态」一致。
六、可审计性是一等目标
论文收束:Linux 实现目标是少于约 4000
行,以便审计与验证。主线合并后代码量有增长,但仍比
IPsec/IKE 用户态+内核总和小一个数量级(本站 内部实现文
对 2026 主线 .c 约 5000 行的统计)。
「少行数」本身不是安全证明。它服务的是哲学目标:一个人或一个小团队能读完实现;协议固定后才谈得上 Tamarin / 计算模型分析(见深度篇)。若为了功能把协商机与证书解析加回来,行数与攻击面会一起回来——那是另一款产品。
七、这套哲学明确不覆盖什么
下列边界来自论文主张与后续工程现实,不是贬义清单:
| 需求 | 为何不匹配 |
|---|---|
| L2 延伸 / VLAN 广播域 | 无稳定「源 IP ↔︎ 公钥」语义 |
| 运行时算法套件协商 | 与 opinionated crypto 冲突 |
| 内核内置证书 PKI | 与 SSH 式带外身份冲突;也回避 ASN.1 解析面 |
| 「拨入即信任」的大平面 VPN 不加分段 | cryptokey routing 只保证接口上源 IP 可信,不替你做应用授权 |
WireGuard 解决的是:在不可信 IP 网上,为已交换公钥的 peer 提供认证、加密、前向保密的 L3 管道,并让管道看起来像网卡。 身份治理、设备姿态、应用层授权属于别的平面。
八、小结
WireGuard 的哲学可以记成四条:
- 公钥即 peer,AllowedIPs 即策略 —— cryptokey routing。
- 管理面无状态外观 —— 握手与漫游藏进内核。
- 密钥分发带外 —— 不造 PKI。
- 密码学固定、版本演进 —— 不造协商机。
下篇从这些公理推出具体消息:Noise IKpsk2 的字段、四次 DH 的属性贡献,以及为何安全数据路径是 1.5 RTT。
参考资料
论文 / 规范
- Donenfeld, J. A. WireGuard: Next Generation Kernel Network Tunnel. NDSS 2017. DOI: 10.14722/ndss.2017.23160.
- Perrin, T. The Noise Protocol Framework. noiseprotocol.org.
相关站内文
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
WireGuard 深度系列:从设计哲学到内核实现
从 Donenfeld NDSS 2017 的设计哲学出发,拆解 Noise IKpsk2、内核数据路径、运维实践与形式化验证争论——把 WireGuard 从「好用的 VPN」讲成可核对的协议与系统。
【WireGuard】协议原理:Noise IKpsk2、四次 DH 与 Cookie
对齐 wireguard.com/protocol 与 NDSS 2017:IKpsk2 消息布局、es/ss/ee/se 四次 DH 的安全贡献、1.5 RTT key confirmation、MAC1/MAC2 cookie,以及 messages.h 中的 rekey 常量。
【WireGuard】深度探讨:形式化证明、密码敏捷性与后量子
Dowling–Paterson 对 1.5 RTT confirmation 的证明障碍、Donenfeld 的回应、netdev 上「无算法协商」争论、PSK 量子权宜之计,以及 WireGuard 作为 ZTNA 数据面的边界与开放问题。
【网络工程】WireGuard 内部实现:Cryptokey Routing、Noise IK 握手与内核数据路径
WireGuard 用不到 4000 行内核代码替代了 IPSec/IKE 数十万行的协议栈——这不是少写功能,而是用固定密码学原语、固定握手模式和 cryptokey routing 这三个设计决定,换掉了证书体系、协商机和 SPD/SAD 分离。本文钻进源码和协议握手过程,逐层拆解 cryptokey routing 的双向执行、Noise IKpsk2 的 1.5 RTT 握手(含四次 ECDH 的安全属性贡献)、内核多核队列架构、timer 状态机、cookie DoS 防御和三密钥对轮换。