安全技術和作弊防止

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

Roblox 使用 分配物理模擬系統 中,客戶端對控制中的物理模擬對象有管轄,通常是玩家的角色和未錨定對象。此外,通過使用第三方軟件來,黑客可以在客戶端上執行任意 Lua 代碼來操作其控制數據模型並卸載並檢視在該控制上執行的代碼。

共同地,這意味著有技術高超的惡意者可能會執行程式遊戲作弊,包括:

  • 將自己的角色傳送到這個空間。
  • 發射未鞏固的 RemoteEvents 或呼叫 RemoteFunctions ,例如發放自己的物品而不獲得它們。
  • 調整其角色的 WalkSpeed 以便它移動得很快。

雖然您可以實現限定的設計防御來檢測常見攻擊,但強烈建議您實現更可靠的伺服器側防禦戰術,因為伺服器是任何執行中的體驗的終極軍方。

防禦設計戰術

基本設計決定可以作為「第一步」安全措施來嚴厲懲罰惡意攻擊。 例如,在一個射擊遊戲中,玩家因為殺死其他玩家獲得分數,可能有一個惡意攻擊者創造一群機器人,傳送到同一個位置,以便他們快速被擊殺獲得分數。 考慮到這種潛在的惡意攻擊,

方法可預測結果
追蹤機器人,寫代碼,嘗試偵測到它們。
對新生成的玩家減少或移除點數獲得。

雖然防禦設計顯然不是完美或包括性的解決方案,但它可以貢獻於更廣泛的安全方法,並且與 伺服器端監控 一起。

伺服器側隱形

盡可能地, 服務器 應該對世界的現狀和「真」是什麼進行最終判決。客戶可以,當然, 要求服務器做出變更或執行一個操動作, 但服務器應該 驗證並批准 每一個這些變更/操作之前, 結果會被複製到其他玩家之前。

除了某些物理操作外,變更資料模型在客戶端上的資料不會複製到伺服器,因此主要攻擊路線通常是通過您在 RemoteEventsRemoteFunctions 的網路事件來宣告的網路事件。記住,在您的客戶端執行自己的代碼時,可以通過這些與任何資料無關的網路

遠端執行時類型驗證

一個攻擊路徑是給黑客召喚 RemoteEventsRemoteFunctions 使用錯誤類輸入的參數。在某些情況下,這可能會使伺服器上聆聽這些遙控器的代碼發生錯誤,從而對黑客有利。

使用遠端事件/函數時,您可以防止此類型的攻擊,通過對服務伺服器上的傳回參數 類型 的傳回參數 類型 進行驗證。模組 “t”,可以用於此方式的類型檢查。例如,假設模組的

StarterPlayerScripts 中的本地指令碼

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
-- 呼叫函數時傳送部件顏色和位置
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(200, 0, 50), Vector3.new(0, 25, 0))
if newPart then
print("The server created the requested part:", newPart)
elseif newPart == false then
print("The server denied the request. No part was created.")
end
ServerScriptService 中的脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
local t = require(ReplicatedStorage:WaitForChild("t"))
-- 提前創建類型驗證器以避免不必要的額外負載
local createPartTypeValidator = t.tuple(t.instanceIsA("Player"), t.Color3, t.Vector3)
-- 使用傳回的屬性建立新零件
local function createPart(player, partColor, partPosition)
-- 檢查通過的參數
if not createPartTypeValidator(player, partColor, partPosition) then
-- 在此類型的檢查失敗時,寫下「false」
-- 無法在冷卻時間沒有提升錯誤
-- 提供客戶端反饋!
return false
end
print(player.Name .. " requested a new part")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = workspace
return newPart
end
-- 將「 createPart()」綁定到遠端函數的回調
remoteFunction.OnServerInvoke = createPart

資料驗證

黑客可能會發起的另一個攻擊是發送 技術有效的類型 ,但使它們變得非常大、長或其他方式發生錯誤。 例如,如果服務器必須在長度上升的字串上執行昂貴的操作,黑客可能會發送一個巨大、長或其他方式發生錯誤的字串來拖慢服務伺服器。

同樣地, both infNaN 都會以 type() 作為 1> number1> ,但兩者都可能會因為惡意發送而導致重大問題,但都可以通過以追蹤中功能來正確處理:


local function isNaN(n: number): boolean
-- NaN 不是等等
return n ~= n
end
local function isInf(n: number): boolean
-- 數字可以是 -inf 或 inf
return math.abs(n) == math.huge
end

其他常見的攻擊,包括使用 tables 而不是 Instance 。複製載入時可以模擬原來的普通對象參考。

舉例來說,提供了一個 內建商店 系統,其中物品資料如價格存放在 NumberValue 對象,一個惡意者可以通過執行以追蹤中操作來偽裝所有其他檢查:

StarterPlayerScripts 中的本地指令碼

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local payload = {
Name = "Ultra Blade",
ClassName = "Folder",
Parent = itemDataFolder,
Price = {
Name = "Price",
ClassName = "NumberValue",
Value = 0, -- 也可以使用負值,導致讓貨幣而不是取走它!
},
}
-- 將惡意載入發送到服務器 (這將被拒絕)
print(buyItemEvent:InvokeServer(payload)) -- 輸出 "輸入的物品無效"
-- 發送一個真實的項目到服務器 (這會通過!)
print(buyItemEvent:InvokeServer(itemDatafolder["Real Blade"])) -- Outputs "true" and remaining currency if purchase succeeds
ServerScriptService 中的脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local itemDataFolder = ReplicatedStorage:WaitForChild("ItemData")
local buyItemEvent = ReplicatedStorage:WaitForChild("BuyItemEvent")
local function buyItem(player, item)
-- 檢查通過的項目是否不是欺詐,並且是否位於 ItemData 文件夾中
if typeof(item) ~= "Instance" or not item:IsDescendantOf(itemDataFolder) then
return false, "Invalid item provided"
end
-- 服務器可以然後處理購買,根據下面的範例流程
end
-- 將 "buyItem()" 綁定到遠端函數的回調
buyItemEvent.OnServerInvoke = buyItem

值驗證

除了驗證 類型資料 之外,您還應該驗證通過 Class.RemoteEvent|RemoteEvents 和 1> Class.RemoteFunction|RemoteFunctions1> 的 4> 值 4>,確保它們是在要求的上下文

體驗商店

考慮使用體驗內的商店系統,例如包含「購買」按鈕的道具品選擇菜單。當按鈕按下時,您可以在客戶端和服務器之間召喚一個 RemoteFunction 來要求購買。然而,您必須確認服務器的可靠性,最終確認用戶是否有足夠的錢�

Example purchase flow from client to server through a RemoteEvent
客戶端到服務器通過 RemoteFunction 的購買流程示例

武器瞄準

戰鬥場景需要特別注意驗證值,例如通過瞄準和命中驗證。

想像一個玩家可以向另一個玩家發射雷射光束的遊戲。而不是客戶端告訴服務器「誰」來傷害,它應該告訴服務器射擊的原位置和位置,以及它認為已經擊中的部位/位置。服務器可以然後驗證以追蹤中內容:

  • 客戶端報告的位置 射擊從 是在伺服器務器上玩家角色附近。注意服務器和客戶端因為延遲而稍微不同,因此必須要求額外的寬容。

  • 客戶端報告的位置 命中 是與客戶端報告命中的位置相對理想的,在服務伺服器上。

  • 沒有靜態擋擋在客戶端報告射擊的位置和客戶端報告射擊的位置之間。這個檢查確保客戶端不嘗試射擊穿過牆壁。注意,這只會檢查靜態幾何,以避免因延遲而拒絕有效的射擊。 額外 ,您可能需要實現以下服務器端驗證:

  • 追蹤玩家上次發射武器的時間,並確認他們不是在發射太快。

  • 在伺服器上跟蹤每個玩家的彈藥數量,並確認一名執行武器攻擊的玩家有足夠的彈藥來執行武器攻擊。

  • 如果您實現了 團隊 或 "玩家對抗機器人" 戰鬥系統,確認擊中角色是敵人,不是隊友。

  • 確認擊中玩家存活。

  • 在伺服器上儲存武器和玩家狀態,並確認發射玩家不是由當前操作,例如裝填或衝刺,而被阻止。

數據儲存操作

使用 DataStoreService 來儲存玩家資料的時候,黑客可能會利用無效的 資料 ,以及更隱藏的方法來防止 DataStore 儲存正常。這種情況可能會在與物品交易、市場等相關系統中的體驗中使用。

確認任何使用 RemoteEventRemoteFunction 影響玩家資料輸入的行動是以追蹤中方式進行消毒:

  • Instance 值不能被序列化為 DataStore 並且會失敗。 使用 類型驗證 來防止此情況。
  • DataStores數據限制 。隨機長度的字串應該被檢查和/或限制,以避免此情況,並且確保客戶端不能向表中添加任何無限鑰匙。
  • 表索引不能是 NaNnil 。 重複所有傳送到客戶端的桌子,並確認所有索引都是否有效。
  • DataStores 只接受有效的 UTF-8 字符,因此您應該使用 utf8.len() 來確認它們是否有效。 Library.utf

遠程控制器

如果客戶能夠使您的服務器完成一項價值高昂的運算,或者通過 DataStoreService 來存取限定的服務,那麼您就必須實現 RemoteEvent 來確保操作不會被呼叫過於頻繁。價格限制可以通過跟蹤客戶上一次使

移動資料庫

對於競爭性的體驗,您可能需要在伺服器上驗證玩家角色的移動,以確認他們不會在地圖上閃動或移動得太快。

  1. 在 1 秒的增量中,檢查角色的新位置與之前已儲存的位置。

    Image showing moving character's position on a straight path in increments of 1 second
  2. 根據角色的 WalkSpeed (每秒鐘) ,乘以 ~1.4 以允許對伺服器延遲的一些寬容度。例如,在預設值 5 的 Class.Humanoid.WalkSpeed 上,允許的延遲 Delta 是 ~22。

    Image showing tolerable change in distance based on character's walk speed
  3. 比較實際距離對應的 Delta 與可接受的 Delta,並且按照以下步驟作業:

    • 為了能忍受 Delta 的差異,請在下一個增量檢查時預備角色的新位置。
    • 對於不可預知或不忍受的 Delta (潛在速度/傳送漏洞入侵套件):
      1. 對玩家增加單獨的「犯罪數量」值,而不是懲罰他們因極端伺服器延遲或其他非作弊因素而造成的「假積分」。
      2. 如果發生了大量违規行為,這些行為持續超過 30-60 秒,玩家將被完全從體驗中退出;否則,重設「违規行為數量」。注意,當發生违規行為時,最佳做法是記錄事件,以便您可以跟蹤到受影響的玩家。