Is this a good way to prevent exploits?

Hey there! So I’m working on scripting an admin panel gui for my game and want to ensure it isn’t vulnerable to exploits. Exploiters having access to an admin panel would be catastrophic, as you can imagine. For this reason, I’m trying to ensure it’s impossible for exploiters to access the panel or execute any of its commands. A friend of mine gave me an idea to secure the panel, and I’d like to know if this method is effective or not.

The method:

[-] The admin panel gui is placed inside of ServerStorage
[-] A script is added to ServerScriptService
[-] The script runs the PlayerAdded() function. Inside of that function, an if statement checks the userIds of every player who joins. If the userId matches one of the admins then the admin panel is cloned and parented to that player’s PlayerGui.

Script:

local serverStorage = game:GetService("ServerStorage")
local adminPanel = serverStorage:WaitForChild("AdminPanel")


game.Players.PlayerAdded:Connect(function(player)
	if player.UserId == *redacted* or player.UserId == *redacted* 
		local newPanel = adminPanel:Clone()
		newPanel.Parent = player.PlayerGui
	end
end)

redacted is just me censoring the userIds of my admins. In the actual script, those are UserIds

3 Likes

ServerStorage cannot be accessed by clients at all, so as long as it is in there, no clients can see it.

Regardless of where Scripts are located, they cannot be decompiled by clients. Only LocalScripts and ModuleScripts can be decompiled by clients. This just ensures that a client cannot see the Script.

The PlayerGui of an individual client does not update across the server, so as long as the server moves it from ServerStorage to the Player’s PlayerGui, other clients will not be able to see it.


However, I propose a different approach. Rather than give the GUI (frontend) total control (such as a button killing a specific player), give the server the control.

Imagine a GUI with a Kill All button. When an someone clicks the button, this is registered on the client, so a RemoteEvent would be required to tell the server when the button is clicked. Move this admin check to the server instead, that way it wouldn’t matter if someone got their hands on the GUI.

Some example code here. Take this LocalScript which listens for a button click, then, fires the AdminCommand RemoteEvent (located in ReplicatedStorage) on the Server.

-- The button that would send an Admin Command over the Server
local AdminCommandButton = script.Parent.AdminCommandButton
-- The RemoteEvent that handles the Admin Command on the Server
local AdminCommandRemoteEvent = game:GetService("ReplicatedStorage").AdminCommand

-- When the AdminCommandButton is clicked...
AdminCommandButton.MouseButton1Click:Connect(function()
	-- Fire the RemoteEvent
	AdminCommandRemoteEvent:FireServer()
	-- You can also pass extra arguments here
	-- See https://create.roblox.com/docs/reference/engine/classes/RemoteEvent#FireClient
end)

And the Server Script which handles the RemoteEvent, invoked by the button in the Admin Only GUI

-- All the Admin UserIds
local Admins = {0, 1, 2}

-- The RemoteEvent that handles any Admin Command Requests from Clients
local AdminCommandRemoteEvent = game:GetService("ReplicatedStorage").AdminCommand

-- The function that is executed when an Admin invokes the RemoteEvent
local function DoAdminCommand(player)
	-- TODO: The Admin Command
	-- You can also pass extra parameters from the RemoteEvent here
	-- See https://create.roblox.com/docs/reference/engine/classes/RemoteEvent#OnServerEvent
end

-- When the RemoteEvent receives a ServerEvent, handle it
-- Where player, is a Player
AdminCommandRemoteEvent.OnServerEvent:Connect(function(player)
	local wasAdmin = false
	-- Iterate through each UserId
	for _, userid in ipairs(Admins) do
		-- Check if player is an Admin
		if player.UserId == userid then
			-- The player is an Admin!
			wasAdmin = true
			DoAdminCommand(player)
			-- Stop iterating in case if the UserId is present in Admins multiple times
			break
		end
	end
	-- At this point, if wasAdmin is false, then someone (who isn't an admin) tried to invoke the Admin ONLY RemoteEvent
	-- We can assume they got their hands on the Admin Only GUI somehow, and we can Kick them for exploiting
	if not wasAdmin then player:Kick("Exploiting") end
end)

This way, even if someone got their hands on the Admin Only GUI, it would be useless to them, as all the commands are locked down on the server. Hope this helps give some insight! :cat:

5 Likes

Thank you for your response! I appreciate all the detail you included. Having the server handle the admin commands is definitely a good idea, but it requires more work. It would be much simpler if it was all handled by the client. If the admin panel is not accessible, which I believe it is not, then you don’t need to server side the commands. I don’t believe it is at all possible to access the gui, so server side commands aren’t necessary.

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.