This is probably not the right place to post it, tell me where to on the comments.
So, I have started working on a admin panel today and managed to add some good features. But, I saw my code was not server-side which I think makes it less secure, so I put it on ServerScriptService and made it server-side, but I decided to use RemoteServers, but I am worried that someone may use RemoteSpy or something to fire my remotes. What is the best way to secure admin code?
Here is the server-side code using RemoteFunction:
local function onSetJumpPower(player, power)
player.Character.Humanoid.JumpPower = power
end
local setJumpPower = game.ReplicatedStorage.SetJumpPower
setJumpPower.OnServerInvoke = function(player, power)
if player.Character then
onSetJumpPower(player, power)
return true
else
return false
end
end
Here is the server-side code:
local function setJumpPower(player, power)
player.Character.Humanoid.JumpPower = power
end
local button = script.Parent
local textBox = button:FindFirstChild("JumpPowerBox")
button.MouseButton1Click:Connect(function()
local input = textBox.Text
local power = tonumber(input)
if power and power >= 0 then
setJumpPower(game.Players.LocalPlayer, power)
else
print("Invalid input:", input)
textBox.Text = "Invalid input"
end
end)
So which is better? How can I secure main panel code? And, are there more secure ways? This is a important aspect, that if in the wrong hands, can be bad.
Check the player’s user id on the server. Exploiters can’t change their user id so you can secure it that way. You could also kick the player if they fire it and are not an admin, because that wouldn’t be possible without exploits.
Be careful with how much of your anti exploit code you share on forums, as exploiters may freely browse these topics. As @jogglejames mentioned, you should check every remote that is fired to see if the user has permission to carry out the command in question. This should be done for all remoteevents, the all remotes are just requests for the server, where the server should decide if it grants the request or not.
Also, the first alternative is way better than the second alternative. As you will require more processing power using the second alternative. A remote an exploiter can’t use doesn’t do any harm, which is the case when using a remote with userid check.
I’d recommend having the GUI in serverstorage, and clone it into the correct players UI. Also utilize remote functions, just as you have, and check if the players have access to do what they request to do. If they don’t you might have found an exploiter
So basically, on the server script whenever the remote event is fired and an if statement and check if the player is an admin. Here’s and example:
local userId = --Your userId
game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player)
if player.UserId == userId then --Check if the player has permission
--Do your stuff
else
player:Kick() --Kick the player if they are an exploiter
end
end)
An Exploiter can join your game with the mod/admin in the server. They can clone the mod/admin Gui to them. If this happen, sanity/security check need to be implemented on the server.
By default, RemoteEvent pass a player who fired it.
You can check the player id on the server. If it match the admin/mod id, proceed with the command.
Else, kick/warn the player instead.
I have added a user ID check, banning the user if they see the UI with invalid ID and it is server-side, I am thinking about adding something else like a secret word for admins.
If it’s a chat command, you can split the message for example:
/kick player : secretcode
-- /kick, is a command
-- player, the targeted player
-- secretcode, a int/string that needed to validate the command. NEED TO BE UNIQUE
You can achieve this by using string.sub,split and more.
Nice, also here is my code, let me know any tips (Kick messages and stuff is changed to avoid exploiters reading this)
local DataStoreService = game:GetService("DataStoreService")
local BanDataStore = DataStoreService:GetDataStore("BannedPlayers")
local Players = game:GetService("Players")
local StarterGui = game:GetService("StarterGui")
local Whitelist = {2899834302}
local adminFunction = Instance.new("RemoteFunction")
adminFunction.Name = "Test"
adminFunction.Parent = game:GetService("ReplicatedStorage")
adminFunction.OnServerInvoke = function(player)
if table.find(Whitelist, player.UserId) then
local admin = StarterGui.EliteAdminGui.EliteAdminButton
admin.Visible = true
admin.Active = true
return true
end
return false
end
local function onPlayerAdded(player)
local userId = player.UserId
local admin = StarterGui.EliteAdminGui.EliteAdminButton
if table.find(Whitelist, userId) then
admin.Visible = true
admin.Active = true
else
admin.Visible = false
admin.Active = false
if admin.Visible then
local success, err = pcall(function()
BanDataStore:SetAsync(tostring(userId), true)
end)
if not success then
warn("Failed to ban player:", err)
end
player:Kick(".")
end
end
end
for _, player in ipairs(Players:GetPlayers()) do
onPlayerAdded(player)
end
Players.PlayerAdded:Connect(onPlayerAdded)
This won’t work, you need to change the value in the PlayerGui, not the StarterGui
local admin = StarterGui.EliteAdminGui.EliteAdminButton
local admin = player.PlayerGui:WaitForChild("EliteAdminGui").EliteAdminButton
And I recommend not to put your admin gui in the StarterGui, but put it in a script and when adding a player, copy it to his PlayerGui folder for safety