How to secure your RemoteEvent and RemoteFunction

Hey developers !

It seems that nobody has yet made a post to fully cover this subject, so I will be doing it. Here’s everything you need to know about how to effectively secure all your RemoteEvents, avoiding queue exhaustion, server crashes, and server-side manipulations.

All security measures are separated into different points. This tutorial include a FREE RESOURCE that uses all these security measures for a RemoteEvent and a RemoteFunction, with explanations at the end of the post. Feel free to let me know if I missed something or if I said something wrong.


⏱️ Cooldowns ⏱️

Security agains't remotes spams

Implementing a cooldown for each player is essential to avoid remote spamming, which could be exploited to make your game lag or even crash the server. Therefore, we’re going to set up a server-side cooldown using a table and tick().

The table will be used to store each player’s UserId and their associated remote cooldown.

The use of tick() will provide a precise decimal value for the passage of time, which will help us compare how much time has elapsed since the last remote call made by the player.

-- This is the table of players and their associated cooldown
local RemoteCooldown = {}

-- Adding a new player to the table, and associate it to the current tick() time
PlayerService.PlayerAdded:Connect(function(NewPlayer)
	RemoteCooldown[NewPlayer.UserId] = tick()
end)

-- Removing an old player of the table
PlayerService.PlayerRemoving:Connect(function(OldPlayer)
	RemoteCooldown[OldPlayer.UserId] = nil
end)

-- Receiving the RemoteEvent signal
RemoteEvent.OnServerEvent:Connect(function(Player)
	-- Checking if the time elapsed since the last player event received is over 0.2 second
	if tick() - RemoteCooldown[Player.UserId] >= 0.2 then
		-- Update the new player tick() time
		RemoteCooldown[Player.UserId] = tick()
	end
end)

☑️ Type Checks ☑️

Security agains't unexpected arguments type

This is the most powerful check you can implement initially, ensuring that all remote arguments are of the expected type. This limits exploiters ability to manipulate them excessively and helps prevent errors.

It is quite simple to implement, you only need to add an additional if statement with typeof().

RemoteEvent.OnServerEvent:Connect(function(Player, Argument1, Argument2)
	-- Checking if the type of Argument1 and Argument2 are the expected ones (a number and a string)
	if typeof(Argument1) == "number" and typeof(Argument2) == "string" then
		print("Arguments type are correct!", Argument1.. " is a number", Argument2.. " is a string")
	else
		warn("Unexpected arguments type! Make sure these are a number and a string", typeof(Argument1), typeof(Argument2))
	end
end)

✅ Sanity Checks ✅

Security agains't arguments manipulations

We are now approaching a tricky but important aspect of security. It’s about checking the remote arguments to ensure they are valid and to identify any potential exploits.

The “basics” of sanity checks simply involve verifying that the arguments are valid and that you can perform actions with them. For example, if you click a GUI button to purchase an item, the arguments would be the item name and the currency name. Therefore, you would search for these datas and check if the player has enough currency to make the purchase and whether they already own the item. NEVER pass numbers as arguments when it comes to changing player data unless it isn’t something important, as this can be easily exploited. Now that I’ve covered the basics, I will focus on other important checks you may not be aware of.

The first important sanity check you have to perform is regarding the length of strings. Many of you may not be aware, but strings can be exploited by passing extremely long and heavy text, which may lag your game or even crash the server if they are used or referenced in a variable. So you can check it using the following methods.

-- This is a table of all expected strings the remote can accept
local ExpectedStrings = {"Hello", "Lol"}

RemoteEvent.OnServerEvent:Connect(function(Player, StringArgument)
	--Method n°1
	if table.find(ExpectedStrings, StringArgument)  then
		print("Okay, this is one of the expected strings")
	end
	
	--Method n°2
	if string.len(StringArgument) <= 10 then
		print("Okay, this is not an unexpected extremely long string to crash the server")
	end
end)

The second sanity check will be about tables. They are an efficient way to transfer a bunch of data from the client to the server, but they are also the most vulnerable. They can be easily manipulated, allowing exploiters to insert anything they want in it, including these extremely long strings. Make sure to NEVER unpack or reference the entire table without first checking the sanity of all its contents. Instead, use only what you need by searching for a specific index name within the table.

RemoteEvent.OnServerEvent:Connect(function(Player, TableArgument)
	-- Method n°1 (array)
	if table.find(TableArgument, "StringOrNumber") then
		print("The needed index exist")
	end
	
	-- Method n°2 (array)
	if table.maxn(TableArgument) <= 5 then
		print("The list is the correct lenght")
		
		for _, Value in TableArgument do
			if typeof(Value) == "Instance" then
				print("The value is the correct type")
			else
				warn("It is an unexpected type and should be removed")
				table.remove(TableArgument, Value)
			end
		end
	end
	
	-- Method n°3 (dictionary)
	if TableArgument["TheNameOfSomething"] and typeof(TableArgument["TheNameOfSomething"]) == "Instance" then
		print("The needed index exist and is the correct type")
	end
end)

📜 New threads 📜

Security agains't server script yield and queue exhaustion

This is not really a must-have feature, but it could be useful in preventing server script yielding and remotes queue exhaustion errors (which occur when a new remote call signal is received while the previous one has not yet ended).

You can use task.spawn() or coroutine or a mix of both, depending on what the RemoteEvent does, your personal preferences, or how familiar you are with them.

RemoteEvent.OnServerEvent:Connect(function(Player, Argument1, Argument2)
	task.spawn(function()
		-- Run everything in a new thread
	end)
end)

RemoteEvent.OnServerEvent:Connect(function(Player, Argument1, Argument2)
	coroutine.create(coroutine.resume(function()
		-- Run everything in a new thread
	end))
end)

📌 Free Resource Here 📌

Here’s a free system I specifically created for this tutorial. It includes all the security measures for a RemoteEvent and RemoteFunction, and uses an advanced and universal method for multi-usage.

Link: https://create.roblox.com/store/asset/75576897903658/Advanced-remotes-system?tab=description

This system is based on all GUI-related events because I thought it would be simpler to understand and to duplicate and adapt for other types of events.

The first argument (ActionType) is a string that defines the selected type of action you want to perform on the Remote. It could be “EquipItem,” “PurchaseItem,” “ToggleSetting,” or any other action you need to perform on the server. This will then initiate a Module function that has the same string/name.

The second argument (DataTable) is a table of data that should contain everything the server needs to perform the specified action. For example, if the ActionType is "EquipItem", the DataTable should contain all necessary information, such as {ItemName = "ClassicSword", SlotNumber = "1"}.

Feel free to ask any questions about this and edit it if you wish.


📌 In Conclusion 📌

Keep in mind that all these server-side security measures can be taken on RemoteEvent, RemoteFunction and UnreliableRemoteEvent.

I hope this tutorial will be useful for most of you and will help secure your game even more! Thanks for reading! :sparkling_heart:

15 Likes

you forgot check for NAN

RemoteEvent:FireServer(0/0,"sigma")

way too much work i doubt it would change anything

adding checks for everything on server can be time consuming especially if youre trying to work on new features you would have to validate everything what would take long time thats why you dont see many big projects care much about exploiters that much they just add anti tp,cooldown and call it a day

1 Like

Woah thanks for the insight!

I made a module similar to this (shameless plug ik ik), I never thought of using tick for the cooldown, Ill try to implement it!

1 Like

I edited the post to make corrections and to add a free resource.
Thanks for the feedback! @FroDev1002 @bura1414

2 Likes