威胁模型
当前状态
初版写于 M0,M1 的实现逐条对照过:哪些要求已经落地、哪些还没有,见对设计的要求。 实现没有经过任何安全审查。
一个直接处理不可信网络输入的程序,安全不能靠事后补。这一页把威胁一条条摆出来, 包括防不住的 —— 知道边界在哪,比相信它无懈可击有用。
如果你发现了这里没写到的问题,请按 SECURITY.md 私下报告。
要保护什么
| 资产 | 丢了意味着什么 |
|---|---|
| 节点私钥 | 别人能冒充这个节点。过去的会话有 WireGuard 的前向安全保护,解不开 |
| 通信内容 | 被读到,或者被篡改 |
| 元数据 | 谁和谁在通信、什么时候、流量多大,以及各自的公网地址(大致能推出位置) |
| 成员关系与访问控制 | 谁在这张网里、谁能访问谁。被篡改就等于有人混了进来 |
| 可用性 | 连不上 |
信任假设
下面的结论都建立在这几条假设上。哪条假设不成立,建立在它上面的结论也就不成立:
- 控制面被信任负责成员与公钥分发。 节点靠控制面知道"某某的公钥是什么"。这是整套设计里信任最集中的地方, 它被攻陷的后果下文单独讨论。控制面可以自建,信不过别人就自己架。
- 中继不被信任。 只指望它尽力转发,内容上一概不信它。
- 节点所在的设备没有被攻陷。 攻击者拿到了设备的管理员权限,这台设备上的一切都保不住。
- 密码学原语和它们的实现可靠:Curve25519、ChaCha20-Poly1305、BLAKE2s,以及 boringtun。自己不写密码学。
按攻击者逐个看
网络路径上的攻击者
公共 Wi-Fi、运营商、路上的任何一台路由器。它能观察、丢弃、注入、重放、篡改经过的报文。
- 拿不到:通信内容。WireGuard 报文加密且带认证,改过的会在对端被丢弃,重放的会被计数器挡掉。
- 看得到:哪个公网地址在和哪个通信、报文的大小和时间,以及"这是 WireGuard / Meshora 流量"—— 报文格式本身就能被识别。报文大小尤其精确:boringtun 不做 WireGuard 规范里的 16 字节填充, 密文长度就是明文长度加 32。
- 设计上的应对:
- 数据面不做漫游,发送路径只由控制面切换(见接口契约)。 扣下报文、换个源地址再放出去,改不了路径
- 控制报文必须经过认证(R3)。否则伪造一条"我的新地址是某某",就能把流量引走
- UDP 被挡时退到中继。这也是为什么中继的传输要考虑能不能穿过只放行 443 端口的网络
- 剩余风险:
- 它总能把流量全部挡掉。如果连到中继的路也被挡了,那就是连不上
- 节点之间的探路报文(Ping)没有防重放。录下一个,换一个伪造的来源地址重放,收到的节点会 回一个 Pong,并把这个地址当候选探测 —— 从没回应过的候选最多探测两次就忘掉,所以一个重放的 报文最多换来三个发往那个地址的小报文。它劫持不了路径:路径要等对方用私钥回应才会被选中, 回应(Pong)也重放不了,每个只认一次
恶意中继
中继可能是别人架的。它能看到经过它的报文,也能决定转不转发。
- 拿不到:内容,理由同上 —— 它转发的是 WireGuard 报文,改不了,重放了也会被计数器挡掉。
- 看得到:元数据。哪两个节点在通信(它得知道报文该交给谁)、时间、流量大小,以及双方的公网地址。
- 设计上的应对:
- 节点连中继时要认证身份(R6)。否则谁都能冒领发给某个节点的报文 —— 读不了,但能让那个节点收不到
- 中继只服务名单里的节点,别人没法白用它的带宽
- 剩余风险:
- 元数据暴露是所有中继方案的共同性质。在意的话就自建中继
- 中继丢包或拖延:控制面经每个中继探测,看得到它们的延迟和丢包,直连或别的中继明显更好时会切走。 打不通直连、协调服务又只给了这一个中继时,只能受着
恶意或被攻陷的控制面
这是整套设计里爆炸半径最大的一处,需要说清楚。
控制面告诉每个节点"网里有谁、各自的公钥是什么"。一个恶意的控制面能:
- 把某个节点的公钥换成自己的,对它做中间人。节点会以为自己在和正确的对端说话
- 把自己的节点塞进网里,或者改掉访问控制
- 看到整张网的拓扑,以及每个节点的公网地址
以现在的设计,这些都防不住。 集中分发公钥的方案都有这个问题,Tailscale 也一样,它后来用 Tailnet Lock 做了缓解。 眼下的应对只有两条:
- 控制面可以自建,把信任留在自己手里
- 节点和控制面之间的握手会认证控制面的身份(见身份认证),网络上的攻击者冒充不了它
怎么降低对控制面的信任,排在开放问题的第一条。
官方服务器(托管很多网络的协调服务)
客户端里"建一个网络"默认用官方服务器:一台服务器跑 meshora-coord --hub,托管很多人的网络 (部署在一台阿里云的服务器上,见桌面客户端)。它就是这些网络的控制面,上一节说的它都能做。 另外要说清楚的:
- 它看得到的元数据:有哪些网络、网络名、谁是网主;每个网络里有谁(公钥、名字、overlay 地址)、 各自的公网地址、什么时候在线;经它的中继转发的流量有多大。看不到游戏内容: 节点之间的报文是 WireGuard 加密的,中继转发的也是密文
- 网络之间互相隔离:一个节点只收得到自己那个网络的 NetMap;服务器带的中继只在同一个网络的成员之间转发, 知道别的网络里某个节点的公钥也转不过去。网络 ID 不是秘密,邀请码才是:只知道网络 ID、没有邀请码又不在名单里,进不去
- 谁都能建网络,所以有滥用面:拿它当免费中继、建一大堆网络把服务器撑爆。限额(
HubLimits,自建时可调):- 一把私钥最多建 3 个网络;同一个公网 IP 一小时最多建 10 个(换私钥绕不过去);整台服务器最多 10000 个
- 一个网络最多 64 人;30 天没人上线的网络自动删掉
- 中继给每个节点限速 4 MB/s
- 剩余风险:来源很多的攻击者(僵尸网络)仍然能在限额内建满网络、占满中继带宽; 限额只是让一个人做不到。服务器运营者能改服务器上的任何东西 —— 信不过的话自己架, 或者本机当主机
网主
托管很多网络时,建网络的人是网主。网主的身份就是建网络时用的那把私钥,服务器只认它。
- 能:移出成员(马上断开)、换长期网络码、发一次性和限时的网络码、作废没用掉的、改网络名、解散网络。 看得到成员名单:名字、overlay 地址、在不在线 —— 这些网里的人本来就互相看得到
- 不能:看到别人的流量;冒用别人的地址;动别的网络。不是网主的人发管理请求,服务器一律拒绝
- 网主的私钥泄漏,拿到它的人就是网主,能把所有人踢掉、解散网络。没有转让网主、多个管理员的办法,以后再说
本机当主机
客户端也能自己当主机:在以管理员身份运行的客户端进程里跑一个协调服务和一个中继, 用 UPnP 让路由器把 TCP 7443、UDP 7443、TCP 7444、UDP 41641 转到这台电脑。于是:
- 协调服务和中继直接暴露在互联网上,跑在管理员进程里。 上面互联网上的任何人那些防护照旧 (握手认证之前不做有副作用的事、限长、限时、按来源限连接数),但它们的代码要是有漏洞, 后果就从"服务器上一个服务被打穿"变成"玩家电脑上的管理员权限被拿走"。这是省掉一台服务器的代价;在意的话用服务器建网络
- 这个协调服务上只有本机那把私钥能建网络;别人知道了地址,也只能凭网络码加入
- 端口映射租期 24 小时,客户端退出时撤掉;客户端被强行结束的话,映射留在路由器上直到租期到
- 它的私钥和网络数据存在
%LOCALAPPDATA%下,和客户端的设置一样:同一个用户的普通进程读得到、改得了
直连模式(不用服务器)
直连模式里没有协调服务、没有中继:房主和每位朋友互发一段连接码,靠打洞直接连上。于是:
- 没有服务器能看到谁和谁联机——上面"恶意或被攻陷的控制面""官方服务器""恶意中继"那几节都不适用
- 公共 STUN 服务器(
stun.miwifi.com、stun.cloudflare.com、stun.l.google.com)看得到你的公网 IP 和端口, 看不到别的。它的回应没有认证:伪造的回应最多让连接码里多一个错的地址,打不通而已—— 客户端只认自己发过的事务 ID、只认发过请求的服务器地址 - 连接码没有签名,只有校验和(发现抄错用)。签名防不了要防的事:能改你们聊天内容的人, 连公钥一起换掉,签名跟着换。码可信全靠传递它的渠道,和网络码一样。房主只加自己亲手贴进去的回执码, 所以只拿到房主码进不来;能篡改聊天内容的人能冒充朋友——把回执码换成自己的,房主一贴就进来了
- WireGuard 握手认的是码里的公钥:码里的公钥不是对方的,就握不上手。打洞用的探测报文和 hub 模式一样, 用双方公钥加密认证
- 房主替朋友们转发:朋友之间的报文在房主那里解密、再加密发给另一位朋友。源地址照样按来源朋友的网段检查, 冒充不了别的朋友;但房主看得到、也改得了朋友之间的明文——和局域网里的网关一样。不信任房主就别让他当房主
- 重启后照着存下的连接码重新打洞,存着的有对方的公网地址和公钥,在客户端的设置文件里,和网络码同等对待
- UPnP / NAT-PMP:直连节点起来后请路由器把它的 UDP 端口转到这台电脑(先试 UPnP,不行试 NAT-PMP,退出时撤掉)。于是互联网上谁都能往这个端口发报文—— 和"本机当主机"开的端口一样,打到的是 Meshora 的数据面:握手认公钥,控制报文认双方公钥,STUN 回应只认自己发过的事务, 都有限速(见下面互联网上的任何人)。同一个局域网里的其他设备也能用 UPnP 改路由器的映射,这是 UPnP 本身的问题
- 公网 IPv6:有的话也写进连接码,直接收发。它和 IPv4 那个端口收到的报文走同一套认证; 路由器的 IPv6 防火墙只放行对方先回应过的,Meshora 不去改它
- 局域网地址:连接码里带上本机每块网卡的局域网地址,拿到码的人能看到你家里的网段
- 一张恶意的连接码能让客户端往哪发包:码是别人给的,里面的地址不全信。读码时就丢掉组播、广播、0.0.0.0 和 1024 以下的端口;对称型 NAT 的端口提示只认对方自己的公网 IP(得是同一张码里某个端点的 IP), 不然一张码就能让客户端在 30 秒里往一个第三方的 IP 扫一大段端口。探测报文本身是加密的,对方解不开
- 打洞代码公开,安不安全:安全靠的是密码学(WireGuard 握手认公钥、探测报文用双方公钥加密), 不靠藏代码 —— 读懂了打洞逻辑也冒充不了你、看不到你们传的东西。代码公开,漏洞才有人帮着找
- Windows 防火墙规则:安装程序加一条只针对
meshora.exe、只放 UDP 的入站规则。放进来的报文同上, 客户端先认证再处理;别的程序不受这条规则影响
互联网上的任何人
协调服务和中继要对外开放 TCP 端口,节点的 UDP 端口谁都能往里发。不在名单里的人:
- 拿不到:任何东西。握手要用名单里的私钥,协调服务和中继在收到第一条加密消息之前不做任何有副作用的事(R1)
- 能:消耗资源,想把服务打挂或者拖慢
- 设计上的应对:
- 握手阶段不按对方自称的长度分配内存:握手消息最多几百字节,握手后的第一条消息最多 64 字节, 超过就断开。握手和第一条消息限时 10 秒
- 文件描述符用完之类的错误不会让协调服务和中继退出
- 同一个来源(IPv4 按地址,IPv6 按 /64)同时最多 16 条连接在握手,多的直接断开。 正常节点握手只要几毫秒,碰不到这个数
- 节点这边:握手报文由 WireGuard 的 cookie 机制限速;控制报文数据面每秒最多交出 1000 条, 控制面在做任何 DH 之前再限到每秒 200 条;协调服务的探测端点每秒最多回应 200 条
- 剩余风险:来源很多的时候(比如僵尸网络),开一大堆连接仍然能占满文件描述符,让新节点暂时连不上 协调服务或中继。已经连上的不受影响,数据面也不经过协调服务
拿到邀请码的人
网络开了邀请加入(协调服务带 --state)时,邀请码就是这个网络的门票:谁拿到带邀请码的网络码, 谁就能加入,成为网内的节点。这和"网络名 + 密码"是一回事,便利换来的就是这个。
- 邀请码 128 位随机数,猜不到;只在 Noise 加密的控制通道里传,协调服务比较时用常数时间。 日志里不打出它(
Debug只显示Invite(..)),客户端界面上也不显示 - 成员上限 1024,一份泄漏的邀请码没法无限制地往网里塞节点、把协调服务拖垮
- 泄漏之后:换邀请码(删掉状态文件里那一行,不用重启),再删掉混进来的成员,它们马上被断开。现在只能这样事后补救, 没有要网络主人确认的邀请。能做的是少发长期有效的网络码:一个人一个一次性的、限时的邀请码 (
meshora-coord invite),泄漏了也只能用那一次、那一阵
网内的恶意节点
一个合法加入、但不怀好意(或者已经被攻陷)的节点。
- 能:访问访问控制允许它访问的一切。M2 做出 ACL 之前,这意味着网里的所有节点。
- 不能:冒用别的节点的 overlay 地址。WireGuard 会丢弃源地址不在对方 AllowedIPs 里的报文, 而 AllowedIPs 由控制面分配,节点自己说了不算。
- 看得到:网里所有成员的公网端点 —— NetMap 会把它们发给每个成员,打洞要用。 换句话说,入网的节点彼此知道对方大致在哪
- 还要防:
- 上报一堆别人的地址当作自己的端点,让其他节点往那里发探测报文。协调服务把每个节点的端点 限制在 16 个以内,并且不收一眼就知道不对的地址(未指定地址、组播、广播、端口 0); 探测报文也很小,但它确实能被当成一个很小的反射源
- 不停地上报新端点,让协调服务给所有人发 NetMap。协调服务把变化合并,给每个节点每秒最多发 一份,而且发的总是最新的那份
- 冒充别人的名字:名字是每个节点自己起的,协调服务只做整理(去掉控制字符、零宽和改变文字方向的字符, 最多 32 个字符),不查重。客户端里名字旁边始终显示地址,认人以地址为准;名字只用纯文本显示, 插不进界面
- 占用中继:托管很多网络时,中继给每个节点限速(默认 4 MB/s);只托管一个网络(
--state、--node)时不限, 成员能用多少带宽就用多少。发给一个收得慢的节点的报文,中继最多替它排 256 个 - 声明中继或出口能力,把别人的流量吸过来;在虚拟局域网里乱发广播。 前者靠能力授权(M3),后者靠广播域和限速(M2)
本机上的其他进程
节点守护进程需要管理员权限(改路由、开虚拟网卡),同一台机器上的普通进程不能借它提权:
- 私钥文件只有守护进程能读。现在 Linux 上发现别人也能读会提醒,Windows 上还不检查
- 本地管理接口(给命令行和图形界面用)必须做访问控制:Windows 上是命名管道的 ACL,Unix 上是 socket 的文件权限(R7)
- Windows 上守护进程以管理员身份加载 wintun.dll。它只从 meshorad.exe 所在的目录加载,不走系统搜索路径, 免得当前目录或 PATH 里一个同名文件被加载(DLL 劫持)。但这也意味着:安装目录必须只有管理员能写, 否则普通用户往里放一个假的 wintun.dll,就能借守护进程拿到管理员权限
- 桌面客户端没有单独的后台服务,节点就跑在以管理员身份运行的客户端进程里。于是:
- 不出免安装版 —— 理由同上,wintun.dll 旁边的目录必须只有管理员能写。安装位置可以改(默认
Program Files\Meshora), 但安装程序会:把Meshora文件夹的所有者改成管理员组、去掉继承来的权限,只给管理员和 SYSTEM 写;并且检查它上面的 每一层,所有者必须是管理员、SYSTEM 或 TrustedInstaller,普通账户不能删除、改名、改权限、删里面的东西 (磁盘根目录的"删除"不算,根目录删不掉)—— 不然别的程序能把整个文件夹挪走、换一个进来。不满足就不装,说出原因。安装程序自己以管理员身份运行,把自己复制成同一目录下的uninstall.exe; 要装的文件(客户端、核对过哈希和 WireGuard LLC 签名的 wintun.dll)是 CI 编进安装程序里的,安装时不联网 - 界面是 WebView2,跑在管理员进程里:界面里的一个脚本注入就等于管理员权限。所以界面只加载编进程序的文件, CSP 只放行自身;所有外来数据(ID、地址、出错信息)一律当文本放进页面,不拼 HTML; 界面能调的命令只有连接、断开、改设置、读状态和日志这几个,碰不到文件和进程
- 私钥和设置存在用户自己的
%LOCALAPPDATA%下。同一个用户的普通进程读得到私钥、改得了设置 (比如把网络码换成别人的协调服务)。这比 R7 要求的弱:要做到"只有守护进程能读",得把节点挪进一个系统服务, 界面只经受访问控制的本地接口和它说话 —— 那是以后的事
- 不出免安装版 —— 理由同上,wintun.dll 旁边的目录必须只有管理员能写。安装位置可以改(默认
安卓上
- 节点跑在 App 进程里,网卡由系统的 VpnService 建,App 不需要 root。VPN 只接管 overlay 网段和广播、组播, Meshora 自己的流量排除在外
- 私钥和设置在 App 的私有数据目录里,别的 App 读不到(手机被 root 了就另说)。卸载 App 会一起删掉
- 界面同样只加载编进 APK 的文件,CSP 只放行自身
私钥泄漏、设备丢失
拿到私钥就能冒充这个节点,直到这把公钥被吊销。WireGuard 的前向安全保证过去的会话解不开。
应对办法是控制面吊销这把公钥,所有节点随后拒绝它。吊销要多久才能传到每个节点,还是开放问题。
供应链
依赖、工具链、CI 都可能被投毒。
- 依赖尽量少,每加一个都要在
Cargo.toml里写明理由。依赖树里的大头是 boringtun, 以及它带进来的一批密码学 crate —— 这是"不自己写密码学"的代价,也正是这条规矩的用意 Cargo.lock入库,CI 一律加--locked;Rust 工具链版本固定- Rust 的 CI 只拿只读权限
- 站点用的 VitePress 依赖树要大得多,但它只影响站点,不会进节点程序
- 剩余风险:GitHub Actions 按大版本号引用,没有按提交哈希固定。大版本标签要是被人改了指向,CI 就会跑别人的代码。
- 自动更新:客户端只装签名对得上的新版本。签名是 Ed25519,签的是"平台、版本号、安装包的 SHA-256", 私钥只在 GitHub 仓库的 Secret 里(发版时 CI 用),公钥写在客户端里。于是:能改 Release 的人、路上改下载内容的人, 换不进别的安装包,也没法拿一个旧的、签过名的安装包冒充新版本。防不住的:拿到这把私钥(或者能改 CI、能读 Secret)的人 能签出客户端会装的东西 —— 和能往仓库里提交代码的人一样,这是信任发版的人。查更新时 GitHub 看得到你的 IP;设置里能关
- 安卓的 APK 用一把固定的钥匙签名,系统只让同一把钥匙签的新版本覆盖安装。这把钥匙也只在仓库的 Secret 里
- 安装程序没有代码签名。下载的人只能拿 Release 里的
SHA256SUMS.txt核对 —— 它和安装程序在同一个地方, 能换掉安装程序的人也能换掉它,所以只防得住下载时出错、镜像被改,防不住 Release 本身被替换
身份认证
节点怎么向控制面证明"我是这把公钥的主人"?用 Noise IK 握手,而不是签名。
WireGuard 的密钥是 X25519,只能做密钥交换,不能直接签名。想要签名,有三条路,各有各的问题:
| 方案 | 问题 |
|---|---|
| 另备一对 Ed25519 密钥专门签名 | "认证和加密用同一对密钥"不成立了,还要多管一把密钥 |
| 身份用 Ed25519,WireGuard 密钥由它换算出来 | 同一个秘密既签名又做 DH,属于跨协议复用,不是好做法 |
| XEdDSA,直接拿 X25519 密钥签名 | 不是标准做法,经过充分审查的实现很少 —— 等于自己写密码学 |
Noise IK 绕开了这个问题:节点拿 WireGuard 用的那对静态密钥,和控制面跑一次握手, 握手能完成就证明它持有私钥。好处有这几个:
- 原语和 WireGuard 是同一套(Curve25519、ChaChaPoly、BLAKE2s)。WireGuard 自己的握手就是 Noise 的 IKpsk2 变体,不引入新的密码学
- 双向认证:按设计,节点事先就知道控制面的公钥(随邀请或配置下发),所以同一次握手也认证了控制面
- 握手一完成就有了加密信道,控制面的通信不必再依赖 TLS 证书体系
- 有先例:Tailscale 的控制协议同样用 Noise IK 认证节点(它用的是一把专门的机器密钥,不是 WireGuard 那把)
代价有两个:
- 给不出能转交第三方验证的签名,比如"这个节点声明了中继能力"这类声明
- 换密钥就等于换身份。公钥即身份,轮换 WireGuard 密钥之后,这个节点在网里就是另一个人了。 Tailscale 把设备身份(机器密钥)和 WireGuard 密钥分成了两把,WireGuard 密钥轮换时设备身份不变
这两点将来需要时都能增量解决:要么加一把签名密钥,要么把身份和 WireGuard 密钥分开。 到那时加进来的东西有明确的用途,而不是现在就多一把用不上的密钥。
同一把节点密钥用在了几种协议里:WireGuard 的握手、控制通道和中继通道的 Noise IK、节点之间控制报文的 Noise K。它们靠各自不同的 Noise 模式和 prologue 做域分离 —— 一种协议里的消息拿到另一种协议里解不开。 协调服务顺带跑中继时,两边共用协调服务的密钥,也是靠这一点隔开。
还有一处细节必须注意:IK 的第一个握手包可以被重放。 攻击者录下某个节点的首包,之后原样发给控制面, 控制面分不出真假。WireGuard 为此在首包里放了时间戳;控制面的做法更简单: 握手完成之前不因为首包做任何有副作用的事,有副作用的请求一律等握手完成、走加密信道再发。
对设计的要求
从上面推出来的硬性要求,以及 M1 实现到了哪一步。"有测试"指的是有专门验证这一条的测试。
| 编号 | 要求 | 现在 |
|---|---|---|
| R1 | 节点和控制面之间用 Noise IK 认证,握手完成前不产生任何副作用 | 已实现,有测试:协调服务和中继都要等到第一条加密消息才登记连接 |
| R2 | 数据面不做漫游,发送路径只由控制面切换 | 已实现,有测试 |
| R3 | 控制报文一律要认证,未经认证的报文不能改变任何状态,还要限速 | 已实现:Noise K 认证,陌生发送方在任何 DH 之前就丢;协调服务的探测端点和节点侧都限速,每秒 200 条。Ping 没有防重放,影响见网络路径上的攻击者 |
| R4 | 同一个网段只能分给一个 peer | 已实现,有测试 |
| R5 | 私钥不出数据面,接口里没有读私钥的方法 | 已实现(接口里没有这样的方法)。控制面持有同一把私钥的另一份,从密钥文件读 |
| R6 | 节点连中继时要认证身份 | 已实现,有测试:中继按节点密钥认证,只服务名单里的节点 |
| R7 | 本地管理接口做访问控制,私钥文件只有守护进程能读 | 部分:Linux 上私钥文件对别人可读时只提醒不拒绝,Windows 上不检查;本地管理接口还不存在。桌面客户端的私钥在用户目录下,同一用户的普通进程读得到 |
| R8 | 依赖尽量少,锁文件入库,CI 加 --locked | 已经在做 |
不防什么
- 匿名。 不隐藏你是谁、在和谁通信。需要匿名请用 Tor 这类工具。
- 流量识别。 别人看得出这是 WireGuard / Meshora 流量。它不是翻墙工具,也不打算伪装。
- 已被攻陷的设备。 攻击者拿到了设备的管理员权限,这台设备上的一切都保不住。
- 量子计算。 X25519 不抗量子。WireGuard 的预共享密钥(PSK)能额外加一层对称加密的保护, 要不要用、怎么分发,是开放问题。
开放问题
- 怎么降低对控制面的信任。 比如让用户带外核对公钥(类似 Signal 的安全码), 或者由离线保管的管理员密钥签署成员变更(类似 Tailnet Lock)
- 身份和 WireGuard 密钥要不要分开,好让密钥轮换不影响身份
- 要不要用 WireGuard 的预共享密钥,用的话怎么分发
- 吊销怎么传播:一把公钥被吊销后,多久能让每个节点都拒绝它?离线的节点回来时怎么办?
- 能不能让中继少知道一点,比如不让它知道报文是从哪个节点来的
- GitHub Actions 要不要按提交哈希固定
欢迎在 Issues 里讨论。安全问题请走 SECURITY.md。
下一步:路线图。