Stop Building Exploits Into Your Game: A Guide On How To Secure Your Server
Hi, My name is jakebball11 and I have been on this platform since 2012 and have been programming for roughly 2 1/2 years. Due to this I have made many mistakes in terms of game security which I hope to show you how to avoid so you dont have to deal with the endless headaches of data exploits.
Prerequisites
This guide is not complicated by any means but since this guide is naturally about securing your server model I am going to assume you have a solid understanding of the Roblox Client-Server Model and how they communicate.
Another thing to understand which is not full made clear in the article is how client data can be changed by exploiters. For example, a remote event the is detect on the server can have data sent to it from the client that was faked. Im sure this wonât cause any isssues down the line so lets move onâŚ
Whats the big deal
Let me give you a common scenario a lot of new programmers have to deal with when learning to use remote events and datastores. Say you make a cool simulator where you scrub cars to get money in which you can buy better tools such as a bigger sponge. You programmed it compelely and are ready for launch so you make it public and let it rip.
-
Day 1, Launch goes great and you are aquiring a solid player base with a good engaging community!
-
Day 2, Its the same as before except now, the players are starting to gain enough money to be on the leaderboard you have setup in game!
-
Day 3, you check in game and see someone has an item that is relatively difficult to get this early but it might be they are just dedicated so you ignore it for now.
-
Day 4, you spot your first data exploiter in game as they now have 100x the amount of coins the top player has even though the exploiter just started playing. You ban him and move on, problem solved, right? Not quite, your code already has a security issue with it and everybody knows it!
-
Day 5, the amount of exploiters grow increasingly large due to the lack of security on the server code and now your community wants answers. You try to hire moderators which works ok but the rate at which exploiters are joining the game naturally the moderation team is overwhelmed.
-
Day 6, Your player base is slowly going down while the exploiters only increase.
-
Day 7, your game is now exploiter full and is basically dead at this point.
What Was The Problem?
Now, what was the issue with that games code? You didnt properly secure the code on the server! Often times what this means is you created remote events that set the server data directly. Lets look back at our previous example. Say this is the client code that gives you coins after you washed your
car.
Client
local Car1Coins = 5
player.Car1WashedEvent:Connect(function()
if player.OwnsCar1.Value == true then
GiveCoinsRemote:FireServer(Car1Coins + player.Coins.Value)
end
end)
Server
GiveCoinsRemote.OnServerEvent:Connect(function(player, coins)
player:SetData("Coins", Coins)
end)
What do you notice about this client code that is wrong? It seems fine right, you check if they own the car and tell the server to give them the coins and we all live happily ever after in a secure world. Not quite.
Remember how I said the client can fake data? An exploiter can simply changed the Car1Value on the client, bypass all the if statements, and then fire the remote events directly.
Now an exploiter can fire it hundreds of times for quick and easy coins even if they dont own the car! As you can see, you programmed the exploit right into the game!
One good way to think about this is as a bank! In this first image we have the bank having a customer wanting to withdraw 5 Million Bucks.
What do you notice about this transaction? The bank didnt check if he had the money! Imagine if bank security worked like this in real life? It would essentially be desiging theft into the banking system. This is what they should be doing instead.
As you can see, checking the amount of money is crucial to a banks secuity. This same principle applies to roblox security. In this case, the server is the bank and the client is the customer. In the bad client code just above the analogy you can see how we arent checking the server to see if they have enough just like how the bad bank analogy isnt checking if the customer has enough.
This is building an easy way to exploit the gameâs coins system directly in the code! What should you do? Well, what does the bank do? They have the teller check if they have the amount before any withdrawl. In this case, you would want the server to check if the client owns the car before giving them the money like so.
Client
player.Car1WashedEvent:Connect(function()
CarWashedRemote:FireServer()
end)
Server
local Car1Coins = 5
GiveCoinsRemote.OnServerEvent:Connect(function(player)
if player.OwnsCar1Value == true then
player:SetData(player.Coins + Car1Coins)
end
end)
As you can see the server is now checking if he owns the car itself instead of blindly trusting the client. If you do this correctly it should be virtually impossible for any exploiters to give themselves any currency or data.
Now, you might think, âcant they spam it now that they own the car giving a lot of money as well?â. Correct! Which is why we need to add debouncing!
Debouncing
What is deboucing? Debouncing is a fancy word for using a bool value to limit time between events. In this case we would need to make a bool value. Since we need one for each player you can either use a table with the values for each player or a BoolValue inside the player instance. We will use the latter for simplictiy sake.
Server
local Car1Coins = 5
GiveCoinsRemote.OnServerEvent:Connect(function(player)
if player.OwnsCar1Value == true then
if player.Debounce.Value == false then
player.Debounce.Value = true
player:SetData(player.Coins + Car1Coins)
end
end
end)
What this is is doing is checking if the debounce value is false. If it is, it makes it true so the player can fire the remote event as much as he wants but wont allow him to give the coins more then once even if he owns the car itself.
This is cool but obviously we want them to scrub the car multiple times. So what we can do is add wait(3) to the end and set it back to false like so.
Server
local Car1Coins = 5
GiveCoinsRemote.OnServerEvent:Connect(function(player)
if player.OwnsCar1Value == true then
if player.Debounce.Value == false then
player.Debounce.Value = true
player:SetData(player.Coins + Car1Coins)
task.wait(3)
player.Debounce.Value = false
end
end
end)
Now, even if he owns the car, he can spam the remote event all he wants but will still be limited to only one coin increment every 3 seconds! The magic of deboucing!
This is the basic idea of server security. ANY transaction of any sort regarding player data or stats should ALWAYS be handled on the server. This is why the term âNever Trust The Clientâ is used all over the programming world including outside of Roblox as the client can send any data it wants including false data the an exploiter wants to pretend he has.
closing
This is a very simple example but should get the point across good enough. This is also my first large tutorial I made so if you have any advice make sure to let me know in the replies!
If you have any questions or want to make improvements to this post feel free to PM me as well!