mcpField
R
roblox-security

roblox-security

github.com/sentinelcoreセキュリティ29719 回インストール35 週間前に更新
リポジトリ

roblox-security について

Roblox 開発者向けに、サーバー側の検証と不正対策を扱うスキルです。重要なゲーム処理をサーバーに置き、クライアントを信頼することで生じる脆弱性を減らします。

主な機能

  1. 01サーバー主導のゲームロジック
  2. 02RemoteEvent 引数の検証
  3. 03プレイヤーごとのクールダウンとレート制限
  4. 04速度とステータスの妥当性確認
  5. 05ModuleScript の安全な配置

活用シーン

  1. 01ダメージ、通貨、購入処理の検証
  2. 02リモート操作やアビリティ使用の確認
  3. 03Roblox ゲームのクライアントとサーバーの境界確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sentinelcore/roblox-skills --skill roblox-security

インストール後、Claude Code で/roblox-securityを入力して読み込まれたか確認します。

詳細

Roblox セキュリティ: エクスプロイト対策とサーバーサイド検証

基本原則

クライアントを決して信頼しないでください。 すべての LocalScript はプレイヤーのマシン上で実行されるため、改変される可能性があります。ダメージ、通貨、ステータス、位置の変更など、すべての権威あるロジックはサーバー上に置く必要があります。

FilteringEnabled は現代の Roblox では常に有効です。サーバーが明示的に適用しない限り、クライアント側の変更はサーバーや他のクライアントに複製されません。


安全なパターンと安全でないパターン

パターン安全でない安全
ダメージの処理LocalScript が Humanoid.Health を設定するサーバーが検証後にヘルスを減少させる
通貨の付与LocalScript が leaderstats をインクリメントするサーバーがアクションを検証してからインクリメントする
Leaderstats の所有権LocalScript が IntValue を所有するサーバーがすべての leaderstats を作成して所有する
位置の変更LocalScript がキャラクターをテレポートさせるサーバーが検証してキャラクターを移動させる
ツールの使用クライアントがヒット時にダメージを発火するサーバーがレイキャストしてダメージを適用する
クールダウンクライアントがクールダウンをローカルで管理するサーバーがプレイヤーごとにクールダウンを管理する

安全な Leaderstats のセットアップ

-- Script in ServerScriptService — never LocalScript
game.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 = leaderstats
end)

サーバーサイドのサニティチェック

距離チェック
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)
クールダウン検証
local ABILITY_COOLDOWN = 5
local 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] = nil
end)
ステータス境界チェック
local MAX_QUANTITY = 99
local 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-side
end)

レート制限

local RATE_LIMIT = 10   -- max calls
local RATE_WINDOW = 1   -- per second
local 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 false
end

ActionRemote.OnServerEvent:Connect(function(player)
    if isRateLimited(player) then return end
    handleAction(player)
end)

game.Players.PlayerRemoving:Connect(function(player)
    callLog[player] = nil
end)

引数検証ユーティリティ

-- ServerScriptService/Modules/Validate.lua
local 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 true
end

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 true
end

function Validate.string(value, maxLength)
    if type(value) ~= "string" then return false end
    if maxLength and #value > maxLength then return false end
    return true
end

return Validate
-- Usage
local 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 proceed
end)

速度 / チート対策検出

local SPEED_LIMIT = 32
local 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
    end
end)

ModuleScript の配置

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

通貨、ダメージ、DataStore のロジックを ReplicatedStorage のモジュールに置かないでください。クライアントが require() できてしまいます。


よくある間違い

間違いなぜエクスプロイト可能か修正
FireServer(damage) をサーバーが信頼するクライアントが任意の値を送信できるサーバーが自身のツールデータからダメージを計算する
通貨を LocalScript の変数に置くクライアントがメモリを変更できるサーバー所有のみにする
発火前のクライアント側距離チェックチェックがバイパス可能サーバーがイベント受信後に再チェックする
RemoteEvent ハンドラにクールダウンがないスパム = 無限のリソースサーバーでプレイヤーごとのクールダウンを設定する
クライアントが設定した WalkSpeed を信頼するクライアントが任意の高い値を設定できるサーバーが WalkSpeed を所有して上限を設ける
ReplicatedStorage モジュールに機密ロジックを置くクライアントが require できるServerScriptService に移動する

コメント