news 2026/9/16 11:11:08

HelloNetcode 安全连接实战:Unity Netcode for Entities 的 TLS 证书与自定义网络驱动接入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HelloNetcode 安全连接实战:Unity Netcode for Entities 的 TLS 证书与自定义网络驱动接入

HelloNetcode 安全连接实战:Unity Netcode for Entities 的 TLS 证书与自定义网络驱动接入

【免费下载链接】EntityComponentSystemSamples项目地址: https://gitcode.com/GitHub_Trending/en/EntityComponentSystemSamples

本文基于 EntityComponentSystemSamples 仓库中 HelloNetcode 系列的08_SecureConnection示例文档编写。该示例演示了如何使用自定义 bootstrapper(引导器)为 Unity Netcode for Entities 的客户端-服务端世界(client/server worlds)启用 TLS 加密连接:通过一个实现INetworkStreamDriverConstructor的自定义驱动构造函数,把客户端 CA 证书、服务端证书与私钥注入到网络驱动中。读完本文,你可以完整理解三个源文件(证书参数、引导器扩展、驱动构造函数)的分工与启用机制,掌握 OpenSSL 生成密钥/证书后在代码中的落地方式,并了解为何该特性必须通过编译宏在全局强制启用。

前置条件:仅依赖 BootstrapAndFrontend 示例

原文档(SecureConnection.md)明确列出本示例的唯一前置依赖:

Only needs the bootstrap to set-up client and server world. * BootstrapAndFrontend

也就是说,只要项目中存在 HelloNetcode 基础篇的01_BootstrapAndFrontend示例所定义的自定义 Bootstrap,就可以叠加本示例。该 Bootstrap 位于 FrontendBootstrap.cs,其核心约定包括:

  • 必须继承ClientServerBootstrap,且整个项目中只能有一个继承它的类(源码注释原文:“The bootstrap needs to extendClientServerBootstrap, there can only be one class extending it in the project”);
  • 需要打上[UnityEngine.Scripting.Preserve]特性,防止 il2cpp 构建在开启裁剪时把 bootstrap 类剥离掉;
  • Initialize(string defaultWorldName)是 Entities 用来创建默认 world 的入口方法。

在 FrontendBootstrap.cs 中,Initialize负责根据启动方式决定创建 Local World(前端菜单、按需创建 client/server world)还是直接CreateDefaultClientServerWorlds()建立 client/server world 并启用 auto-connect(默认端口 7979,可用命令行-port 8000覆盖)。安全连接示例正是建立在这套 world 创建流程之上,只是替换了驱动层的默认实现。

需要说明的一点:NetCode 包本身的连接建立、client/server world 分离、网络连接与 Secure Connection 等详细指南以官方文档为准(原文档给出了对应的手册链接:Getting Started 的 "Establish a connection" 一节、Client Server Worlds、Network Connection、以及 Transport 包的 Secure Client and Server 与 "Generate Required Keys and Certificate" 小节),本文只聚焦仓库内示例代码本身的实现。

示例总体结构:无场景、纯代码修改

原文档 "Sample description" 部分强调了两点关键特性:

  1. 本示例不包含任何场景——启用安全连接不需要往场景中添加任何东西("This sample contains no scene as nothing needs to be added to the scene to enable this feature");
  2. 必须在 bootstrap 阶段替换默认驱动——要在网络驱动上配置安全连接参数,就需要一个 custom/manual driver,以便向它传入不同的网络参数。而自定义驱动构造函数必须在 bootstrap 中足够早地注册,早于 world 创建,这样才能替换默认驱动。

目录 NetcodeSamples/Assets/Samples/HelloNetcode/2_Intermediate/08_SecureConnection/ 下恰好只有三个 C# 文件,分别承担三个职责:

文件职责
NetworkParams.cs存放本示例已生成的 TLS 证书、服务端证书与私钥(PEM 格式静态字符串)
SecureBootstrapExtension.cs继承自FrontendBootstrap的扩展类,在Initialize中把安全驱动构造函数挂到NetworkStreamReceiveSystem
SecureDriverConstructor.cs实现INetworkStreamDriverConstructor,把证书参数传给网络驱动

三个文件全部被同一个编译宏ENABLE_NETCODE_SAMPLE_SECURE包裹。每个文件的第 1 行都写着被注释掉的宏定义:

//#define ENABLE_NETCODE_SAMPLE_SECURE

原文档解释了启用方式:把ENABLE_NETCODE_SAMPLE_SECURE这一行在三个文件中同时取消注释即可。注释中还给出了重要原因——一旦启用,它就全局地作用于整个项目("since enabling it means it's enforced globally through the whole project")。这与"项目中只能有一个 bootstrap"的约束直接相关:SecureBootStrapExtension继承自FrontendBootstrap,如果它与主 bootstrap 同时生效,项目中就出现了两个继承ClientServerBootstrap的类。因此该宏实际上是"以本示例的 bootstrap 替换主 bootstrap"的全局开关。

生成安全参数:NetworkParams.cs 中的证书与私钥

原文档 "Generating secure parameters" 一节说明:在NetworkParams.cs中可以看到一组静态变量,里面是本示例自己生成的证书;你自己的游戏需要自行生成,方法参考 Transport 文档中 "Generate Required Keys and Certificate" 的 OpenSSL 流程。

对应源码 NetworkParams.cs 中的SecureParameters静态类包含四个字段,全部在#if ENABLE_NETCODE_SAMPLE_SECURE条件编译内部:

  • ServerCommonNameFixedString512Bytes,值为"hello_netcode_secure",即用于定义服务端证书的 Common Name(CN)。客户端在握手时会用这个名字来校验服务端身份;
  • GameClientCAFixedString4096Bytes游戏客户端信任的 CA 证书(PEM 文本,-----BEGIN CERTIFICATE----------END CERTIFICATE-----);
  • GameServerCertificateFixedString4096Bytes服务端证书(同样 PEM 文本);
  • GameServerPrivateFixedString4096Bytes服务端 RSA 私钥-----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY-----)。

从源码结构看,这里选用FixedString512Bytes/FixedString4096Bytes这类Unity.Collections的定长字符串类型来承载 PEM 文本,是为了在 Burst/Jobified 友好的原生内存中传递证书数据,避免在驱动创建路径上额外分配托管字符串。

该文件开头的 XML 注释原样重申了原文档最重要的安全告警:

DO NOT SHIP GENERATED PRIVATE KEYS AS PART OF YOUR GAME!

原文档(SecureConnection.md)中的完整 NOTE 是:发布游戏时不要把你的生成密钥和证书随包发布——即使代码经过混淆,恶意用户也很容易反编译出密钥。仓库中还有一处呼应:SecureBootstrapExtension.cs 的Initialize开头在非编辑器构建(!UNITY_EDITOR)下会输出SAMPLE CODE: don't ship the certificates as a part of your build的警告/错误日志,其中在定义了NETCODE_DEBUG时用LogWarning,否则用LogError,作为运行时再提醒。实际项目中应改为服务端签发/下发证书,而不是把私钥硬编码在客户端代码里。

注册驱动构造函数:SecureBootstrapExtension.cs

SecureBootstrapExtension.cs 全文如下(去除条件编译与注释后的核心逻辑):

[UnityEngine.Scripting.Preserve] public class SecureBootStrapExtension : FrontendBootstrap { public override bool Initialize(string defaultWorldName) { // 在 world 创建之前把自定义驱动构造函数挂上去 NetworkStreamReceiveSystem.DriverConstructor = new SecureDriverConstructor(); return base.Initialize(defaultWorldName); } }

源码注释解释了为什么写在这里:Netcode bootstrap 已经定义在 01 主连接示例中,而一个项目里只能有一个 bootstrap,所以这里只是在现有NetCodeBootstrap类的基础上"叠加"这一行("normally a project would only have the boostrap defined in one place")。关键调用链是:

  1. Initialize被 Entities 引导流程调用(见 FrontendBootstrap.cs 中的注释 "The initialize method is what Entities calls to create the default worlds");
  2. base.Initialize内部真正创建 client/server world 之前,先把NetworkStreamReceiveSystem.DriverConstructor静态字段替换为SecureDriverConstructor实例;
  3. 之后 world 创建路径读取该构造函数时,拿到的就是带 TLS 参数的驱动注册逻辑。

NetworkStreamReceiveSystem.DriverConstructor是一个可全局替换的静态挂载点。仓库中其他示例也依赖同一机制来切换驱动实现,例如:

  • RelayDriverConstructor.cs(Relay 支持示例);
  • HostMigrationHelper.cs 中MigrateDataToNewServerWorld会先保存旧构造函数、临时替换、再恢复(var oldConstructor = NetworkStreamReceiveSystem.DriverConstructor;…),说明该字段是"当前生效驱动构造函数"的单一入口。

这可以推断出一个实用技巧:DriverConstructor支持运行时临时替换与还原,但安全连接示例选择的是"bootstrap 阶段一次性全局替换"这种最简方式。

传递安全参数:SecureDriverConstructor.cs

原文档 "Passing secure parameters" 一节说:生成的证书在SecureDriverConstructor.cs中被传入网络驱动,这里使用了一个 helper function 来为网络设置填充默认值;你也可以改为手动构造网络驱动实例,或通过相应的 override 传入自己的网络设置。

对应源码 SecureDriverConstructor.cs:

/// <summary> /// Register client and server using TLS configuration. /// The configuration is retrieved from <see cref="SecureParameters"/>. /// </summary> public struct SecureDriverConstructor : INetworkStreamDriverConstructor { public void CreateClientDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) { DefaultDriverBuilder.RegisterClientDriver( world, ref driverStore, netDebug, caCertificate: ref SecureParameters.GameClientCA, serverName: ref SecureParameters.ServerCommonName); } public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) { DefaultDriverBuilder.RegisterServerDriver( world, ref driverStore, netDebug, certificate: ref SecureParameters.GameServerCertificate, privateKey: ref SecureParameters.GameServerPrivate); } }

要点:

  • INetworkStreamDriverConstructor接口有两个必须实现的方法:CreateClientDriverCreateServerDriver,分别负责为指定World注册客户端/服务端网络驱动;
  • 客户端侧通过DefaultDriverBuilder.RegisterClientDriver的可选参数caCertificate(CA 证书)与serverName(即ServerCommonName,用于证书 CN 校验)启用 TLS 客户端驱动;
  • 服务端侧通过DefaultDriverBuilder.RegisterServerDriver的可选参数certificate(服务端证书)与privateKey(私钥)启用 TLS 服务端驱动;
  • DefaultDriverBuilder正是原文档所说的 "helper function to set up default values on the network settings",它在内部按平台/运行模式组装默认的NetworkSettings并注册对应传输(IPC/UDP/WebSocket 等)。

对比仓库中不启用 TLS 的自定义构造函数实现,可以更清楚地看出安全连接示例的"增量"所在:

  • CustomHandlers.cs 中的CustomDriverConstructor手动GetNetworkSettings()后按平台分派到RegisterClientIpcDriver/RegisterClientUdpDriver/RegisterClientWebSocketDriver(服务端同理);
  • RelayDriverConstructor.cs 则按 IPC(编辑器本地)与 UDP/WebSocket(Relay 路径)组合注册;
  • ConnectionMonitorSystem.cs 的DriverConstructor演示了根据模拟器管线需求选择CreateClientSimulatorPipelines/CreateClientPipelines/CreateServerPipelines

SecureDriverConstructor选择直接调用RegisterClientDriver/RegisterServerDriver这两个高层入口,只在参数上追加证书信息,是最简的 TLS 接入写法。若你需要自定义 MTU、传输类型、QoS 等更多网络参数,原文档给出的方向是"manually construct the network driver instance, or pass in your own network settings using the appropriate override",即参考上述示例中GetNetworkSettings()+ 分平台Register*Driver的做法,把证书参数与自定义设置合并。

启用步骤与注意事项汇总

结合原文档与源码,完整启用流程与约束如下:

  1. 确认前置:项目使用01_BootstrapAndFrontend示例的FrontendBootstrap(或其等价自定义 bootstrap)。本示例不新增场景,不需要任何编辑器操作;
  2. 生成你自己的证书:按 Transport 文档用 OpenSSL 生成 CA、服务端证书与私钥(本仓库示例已内置一份生成好的,仅用于演示);
  3. 填入参数:把 PEM 文本与 CN 写入NetworkParams.csSecureParameters四个字段(客户端 CA、服务端证书、服务端私钥、ServerCommonName);
  4. 开启编译宏:在NetworkParams.csSecureBootstrapExtension.csSecureDriverConstructor.cs三个文件中,把首行//#define ENABLE_NETCODE_SAMPLE_SECURE取消注释。三个文件必须同时开启,否则SecureDriverConstructorSecureParameters会因条件编译被整体裁掉;
  5. 理解全局性:该宏是项目级全局生效的,SecureBootStrapExtension会作为继承自FrontendBootstrap的第二个 bootstrap 存在——这正是仓库用条件编译而非直接生效的原因;
  6. 发布安全:绝不要把生成好的私钥/证书随构建发布,防止反编译泄露(源码注释与运行时日志均强调此点)。

适用前提说明:本示例基于仓库中当前版本的 Netcode for Entities API(INetworkStreamDriverConstructorNetworkStreamReceiveSystem.DriverConstructorDefaultDriverBuilder),接口签名以仓库内 SecureDriverConstructor.cs 为准;不同版本的 Netcode/Transport 包中这些入口可能有变动,迁移时应以所用包版本的手册为准。

【免费下载链接】EntityComponentSystemSamples项目地址: https://gitcode.com/GitHub_Trending/en/EntityComponentSystemSamples

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 11:10:46

侧信道攻击防御技术:从原理到工程实践

1. 侧信道攻击防御技术概述在加密系统安全领域&#xff0c;侧信道攻击&#xff08;Side-channel Attack&#xff09;已经成为传统密码分析的致命补充。与直接破解算法不同&#xff0c;这类攻击通过采集加密设备运行时的物理特征——如执行时间、功耗波动、电磁辐射甚至声音信号…

作者头像 李华
网站建设 2026/9/16 11:09:35

Claude Code逆向工程:AI编码助手实现解析

1. 项目概述&#xff1a;Claude Code逆向工程学习项目这个开源项目完整复现了Claude Code的25核心工具实现&#xff0c;基于TypeScriptReact Ink技术栈&#xff0c;为开发者提供了一个深入理解AI编码Agent内部机制的绝佳学习资源。作为一个长期从事前端工程化和AI应用开发的工程…

作者头像 李华
网站建设 2026/9/16 11:08:50

Vert.x 4中RoutingContext接口解析与实战应用

1. Vert.x 4中RoutingContext接口深度解析在Vert.x 4.x的Web开发框架中&#xff0c;RoutingContext接口扮演着HTTP请求处理管道的核心角色。作为一位长期使用Vert.x构建高并发服务的开发者&#xff0c;我发现这个接口的设计精妙地融合了异步非阻塞特性与灵活的路由控制能力。它…

作者头像 李华
网站建设 2026/9/16 11:08:07

明星签名照鉴定技术与市场风险解析

1. 明星签名照鉴定需求解析在收藏品市场中&#xff0c;明星签名照一直保持着稳定的热度。去年某拍卖会上&#xff0c;一张知名歌手的亲笔签名照以5.8万元成交&#xff0c;而同期出现的赝品在鉴定后价值归零——这个真实案例揭示了签名鉴定行业的价值所在。作为从业十余年的收藏…

作者头像 李华