Roblox Security

sentinelcore/roblox-skills/roblox-security

作者 sentinelcoref2b1910a7fb898ed35cf2f856e2a2e48e38276bf無授權條款收錄於 2026年10月9日更新於 2026年10月9日

Use when writing Roblox game scripts that handle player actions, currencies, stats, damage, or any RemoteEvent/RemoteFunction communication. Use when reviewing code for exploitable patterns, implementing anti-cheat logic, validating client requests on the server, or setting up rate limiting.

AI 產生的概覽

指導撰寫與審查 Roblox 遊戲腳本,實作伺服器端驗證、反作弊與速率限制。

功能
此技能提供用於保護 Roblox 遊戲腳本免於用戶端漏洞利用的指引與程式碼模式。它對比傷害、貨幣、leaderstats、位置變更與冷卻時間的不安全與安全寫法,並提供伺服器端合理性檢查、參數驗證、速率限制、速度偵測與模組放置的 Lua 範例。它也列出常見的可利用錯誤及其修正方式。
適用情境
在撰寫處理玩家動作、貨幣、屬性、傷害或 RemoteEvent/RemoteFunction 通訊的 Roblox 腳本時使用。在審查 Roblox 程式碼中的可利用模式、加入反作弊邏輯、在伺服器端驗證用戶端請求,或設定速率限制時使用。
執行需求
此技能不隨附腳本或資源,僅為指示文件與 Lua 程式碼範例。它假定具備支援伺服器端腳本的 Roblox 開發環境(ServerScriptService、RemoteEvents/RemoteFunctions)。

Roblox Security: Anti-Exploit & Server-Side Validation

Core Principle

Never trust the client. Every LocalScript runs on the player's machine and can be modified. All authoritative logic — damage, currency, stats, position changes — must live on the server.

FilteringEnabled is always on in modern Roblox. Client-side changes do not replicate to the server or other clients unless the server explicitly applies them.


Secure vs Insecure Patterns

PatternInsecureSecure
Dealing damageLocalScript sets Humanoid.HealthServer reduces health after validation
Awarding currencyLocalScript increments leaderstatsServer validates action, then increments
Leaderstats ownershipLocalScript owns the IntValueServer creates and owns all leaderstats
Position changesLocalScript teleports characterServer validates and moves character
Tool useClient fires damage on hitServer raycasts and applies damage
CooldownsClient tracks cooldown locallyServer tracks cooldown per player

Secure Leaderstats Setup

lua
-- Script in ServerScriptService — never LocalScriptgame.Players.PlayerAdded:Connect(function(player)    local leaderstats = Instance.new("Folder")    leaderstats.Name = "leaderstats"    leaderstats.Parent = player
    local coins = Instance.new("IntValue")    coins.Name = "Coins"    coins.Value = 0    coins.Parent = leaderstatsend)

Server-Side Sanity Checks

Distance Check

lua
local MAX_INTERACT_DISTANCE = 10
InteractRemote.OnServerEvent:Connect(function(player, targetPart)    if typeof(targetPart) ~= "Instance" or not targetPart:IsA("BasePart") then return end
    local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")    if not root then return end
    if (root.Position - targetPart.Position).Magnitude > MAX_INTERACT_DISTANCE then        warn(player.Name .. " sent interaction from invalid distance")        return    end
    processInteraction(player, targetPart)end)

Cooldown Validation

lua
local ABILITY_COOLDOWN = 5local lastUsed = {}
UseAbilityRemote.OnServerEvent:Connect(function(player)    local now = os.clock()    if now - (lastUsed[player] or 0) < ABILITY_COOLDOWN then return end    lastUsed[player] = now    applyAbility(player)end)
game.Players.PlayerRemoving:Connect(function(player)    lastUsed[player] = nilend)

Stat Bounds Check

lua
local MAX_QUANTITY = 99local ITEM_COST = 50
BuyItemRemote.OnServerEvent:Connect(function(player, quantity)    if type(quantity) ~= "number" then return end    quantity = math.clamp(math.floor(quantity), 1, MAX_QUANTITY)
    local coins = player.leaderstats.Coins    if coins.Value < ITEM_COST * quantity then return end
    coins.Value = coins.Value - (ITEM_COST * quantity)    -- award items server-sideend)

Rate Limiting

lua
local RATE_LIMIT = 10   -- max callslocal RATE_WINDOW = 1   -- per secondlocal callLog = {}
local function isRateLimited(player)    local now = os.clock()    local log = callLog[player] or {}    local pruned = {}    for _, t in ipairs(log) do        if now - t < RATE_WINDOW then table.insert(pruned, t) end    end    if #pruned >= RATE_LIMIT then        callLog[player] = pruned        return true    end    table.insert(pruned, now)    callLog[player] = pruned    return falseend
ActionRemote.OnServerEvent:Connect(function(player)    if isRateLimited(player) then return end    handleAction(player)end)
game.Players.PlayerRemoving:Connect(function(player)    callLog[player] = nilend)

Argument Validation Utility

lua
-- ServerScriptService/Modules/Validate.lualocal Validate = {}
function Validate.number(value, min, max)    if type(value) ~= "number" then return false end    if value ~= value then return false end -- NaN check    if min and value < min then return false end    if max and value > max then return false end    return trueend
function Validate.instance(value, className)    if typeof(value) ~= "Instance" then return false end    if className and not value:IsA(className) then return false end    return trueend
function Validate.string(value, maxLength)    if type(value) ~= "string" then return false end    if maxLength and #value > maxLength then return false end    return trueend
return Validate
lua
-- Usagelocal Validate = require(script.Parent.Modules.Validate)
remote.OnServerEvent:Connect(function(player, amount, targetPart)    if not Validate.number(amount, 1, 100) then return end    if not Validate.instance(targetPart, "BasePart") then return end    -- safe to proceedend)

Speed / Anti-Cheat Detection

lua
local SPEED_LIMIT = 32local violations = {}
task.spawn(function()    while true do        task.wait(2)        for _, player in ipairs(game.Players:GetPlayers()) do            local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")            if root and root.AssemblyLinearVelocity.Magnitude > SPEED_LIMIT then                violations[player] = (violations[player] or 0) + 1                if violations[player] >= 3 then                    player:Kick("Cheating detected.")                end            else                violations[player] = math.max(0, (violations[player] or 0) - 1)            end        end    endend)

ModuleScript Placement

ServerScriptService/  Modules/    DamageCalculator.lua   -- server-only, never exposed to client    EconomyManager.lua     -- server-only
ReplicatedStorage/  Remotes/                 -- RemoteEvent/RemoteFunction instances only  SharedModules/           -- non-sensitive utilities only

Never put currency, damage, or DataStore logic in ReplicatedStorage modules — clients can require() them.


Common Mistakes

MistakeWhy It's ExploitableFix
FireServer(damage) with server trusting itClient sends any valueServer calculates damage from its own tool data
Currency in LocalScript variableClient can modify memoryServer-owned only
Client-side distance check before firingCheck is bypassableServer re-checks after receiving event
No cooldown on RemoteEvent handlersSpam = infinite resourcesPer-player cooldown on server
Trusting WalkSpeed set by clientClient sets arbitrarily highServer owns and caps WalkSpeed
Sensitive logic in ReplicatedStorage moduleClients can require itMove to ServerScriptService

來源與署名

來源:sentinelcore/roblox-skills位於roblox-security提交f2b1910

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架