访问控制和机密性

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

了解哪些信息和资产对客户端可见对于维护您体验的安全性和机密性至关重要。开发者往往低估了可被利用者看到和复制给客户端的信息量。如果利用者能够加入一个地点,他们就有能力访问您宇宙内的“受限”地方。他们可以查看复制到其客户端的任何内容,无论其是否可见或当前是否在使用。此外,利用者可以反编译任何已复制的本地脚本和模块脚本,即使它们从未在客户端上执行。

宇宙内的客户端传送

一旦进入宇宙,客户端可以传送到该宇宙内的任何地点,从而可能绕过任何预设的访问限制或进展门槛。这也可能导致未发布内容的意外泄露,例如来自开发或临时体验。重要的是要理解:

  • 禁用“直接访问”仅会从网站上的子地方移除加入按钮 — 它并不会阻止客户端发起的传送
  • 假设利用者会发现您宇宙内所有子地方的存在
  • 客户端可以传送到任何子地方,如果他们能访问单个地方,如根地方,无论您预设的设计流程是什么

许多开发者试图通过踢出未授权用户来防止访问某个子地方。这可能有效阻止游戏玩法,但不会阻止内容复制到客户端,因为复制在玩家加入后立即开始,并在服务器端踢出逻辑执行之前。

使用安全传送

通过在创建者仪表盘上将地点的访问控制设置为仅在宇宙内安全,可以有效防止通过传送未授权访问。这只允许服务器发起的传送到非起始地点,在玩家加入子地方之前,在平台级别阻止客户端发起的传送。由于玩家从未加入,因此没有内容复制到他们。

有关配置步骤和现有体验的迁移指南,这些体验使用客户端发起的传送,请参见地点之间的传送

针对受限地点的深度防御

对于无法使用安全传送的宇宙,或作为额外的保护层,结合以下措施:

  • 将开发和测试地点保存在单独的私有宇宙中 — 这是确保未发布内容机密性的唯一可靠方法。在这些内容预定激活之前,切勿将机密事件资产、脚本或UI元素发布到生产环境。
  • 如果可行,使用流式处理限制新玩家复制的世界量。
  • 添加服务器端组角色或徽章验证,并验证玩家状态或进展要求。
  • 默认情况下,禁止incoming玩家。这确保了即使验证过程得出的结果不确定,如引擎抛出异常的情况,也不会允许任何玩家进入。
  • 如果实际可行,使用Ban API禁止未通过验证的玩家。这防止玩家持续尝试使用同一账户加入。

复制

复制描述了状态如何在引擎实例之间通过网络传输。Roblox的复制模型通常在几个关键方面简化:

  • 实例具有服务器授权,这意味着为了在所有参与者(服务器和所有连接的客户端)之间复制一个实例,它必须在服务器上创建。
  • 实例属性也是服务器授权的,这意味着大多数属性必须在服务器上更改,以便在所有客户端上可见更改。
  • 一般来说,实例要么复制到所有连接的客户端,要么不复制。有一些例外,例如流式。

复制容器是顶级实例(父级为DataModel),它们复制到客户端。如果一个实例在其生命周期中成为复制容器的后代,您应该期望其大部分状态复制到所有客户端。您可以在数据模型指南中阅读有关常见复制容器的更多信息。在有疑问时,您总是可以检查实例或属性在测试环境(例如Play Solo)中的复制方式。您可以在Studio测试模式中阅读有关测试模式的更多信息。

复制的安全影响

任何复制到客户端的内容都可以被利用者提取和数据挖掘。一般规则是避免将任何机密内容发布或运送到实时生产环境,除非您已经准备好让用户看到它。即使在体验中有逻辑限制内容的发布或访问直至较晚的日期(或其他某种条件),也请假设利用者会找到方法在内容发布的瞬间发现并泄露它。

避免对敏感实例使用过于详细或可预测的名称,包括但不限于:脚本、远程和模型。可预测的数据模型层次让开发利用变得更容易。

脚本反编译

任何复制到其客户端的LocalScriptScript(带有RunContext::Client)或ModuleScript都可以被利用者反编译,即使这些脚本被禁用、从不需要或从未在客户端上运行。存储在ServerStorageServerScriptService中的仅服务器脚本和模块脚本不能被反编译,因为它们从未复制到客户端。

在同一个脚本中编写同时包含仅服务器和仅客户端代码的模块脚本是不建议的,因为服务器端逻辑将在反编译中暴露,并且利用者更容易分析其中的漏洞。

原始ModuleScript在ReplicatedStorage中

local module = {}
local Remote = script:WaitForChild("RemoteEvent")
-- 这是一个要避免的范例
-- 将服务器代码保存在Script实例或在ServerStorage/ServerScriptStorage中!
if game:GetService("RunService"):IsServer() then
function module:DoServerThing(password)
if password == "SecretPassword" then
print("敏感的服务器代码")
end
end
Remote.OnServerEvent:Connect(function(player, password)
module:DoServerThing(password)
end)
else
function module:DoServerThing(password)
Remote:FireServer(password)
end
end
return module
反编译结果

local table1 = {};
local RemoteEvent = script:WaitForChild("RemoteEvent");
if game:GetService("RunService"):IsServer() then
function table1.DoServerThing(_, p2) -- 第9行
if p2 == "SecretPassword" then
print("敏感的服务器代码");
end
end
RemoteEvent.OnServerEvent:Connect(function(player: Player, p3) -- 第15行
--[[
上下文变量:
[1] = table1
--]]
table1:DoServerThing(p3);
end);
return table1;
end
function table1.DoServerThing(_, p1) -- 第19行
--[[
上下文变量:
[1] = RemoteEvent
--]]
RemoteEvent:FireServer(p1);
end
return table1;

如上所示,反编译揭示了包括硬编码密码、业务规则和实施细节的服务器端逻辑,这些都是利用者可以分析的漏洞。

机密性泄露的影响

机密性泄露可能会带来重大后果,例如:

  • 内容泄露:未发布的物品、地图或功能可能在正式公告之前被发现并公开分享
  • 竞争劣势:竞争对手可能会对机制、算法或即将推出的功能进行逆向工程
  • 利用开发:暴露的服务器逻辑使得利用者更快、更容易识别漏洞并开发有针对性的攻击
©2026 Roblox Corporation、Roblox、Roblox 标志及 Powering Imagination 是我们在美国及其他国家或地区的注册与未注册商标。