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 从公开仓库中收录这些内容。

举报或申请下架