How to use RemoteEvents properly
a guide written by
Kampfkarren
This assumes that you use FilteringEnabled. If you don't, you should.
It's a common misconception that FilteringEnabled stops hackers. It doesn't. That's not its job. FilteringEnabled stops hackers from having their hacks replicate to other clients. FilteringEnabled does not stop hackers from injecting Lua code. This is why it is important that your RemoteEvents are secure.
There are three golden rules about networking.
- Never trust the client.
- Never give the client too much power.
- Everything that can securely be handled on the client should be handled on the client.
Never Trust the Client
By "never trust the client", I mean never trust the client.
Let's say I had a Server Script that lets players deposit money into their bank accounts.
1 | game:GetService( "ReplicatedStorage" ).DepositMoney.OnServerEvent:Connect( function (ply, num) |
2 | ply.Moneyz.Value = ply.Moneyz.Value - num |
3 | ply.Bank.Value = ply.Bank.Value + num |
Do you see the problem? We don't check if the number is at all valid. Do we check if it's a number? No. Do we check if it's negative? No. Do we check if they have enough in their account? No.
A hacker can run this line of code:
1 | game:GetService( "ReplicatedStorage" ).DepositMoney:FireServer(- 999999 ) |
And they'd be RICH!
What's the solution? Easy.
1 | game:GetService( "ReplicatedStorage" ).DepositMoney.OnServerEvent:Connect( function (ply, num) |
2 | if typeof(num) ~ = "number" then return end |
3 | if num < 0 then return end |
5 | if ply.Moneyz.Value > = num then |
6 | ply.Moneyz.Value = ply.Moneyz.Value - num |
7 | ply.Bank.Value = ply.Bank.Value + num |
Get the point? Never trust the client. Make absolutely sure their inputs are valid before doing what you want.
Never Give the Client Too Much Power
Let's say we had a gun, but because we want to avoid latency, we handle all the firing on the client.
3 | tool.Activated:Connect( function () |
4 | for _,victim in pairs (getEnemiesInFiringRange()) do |
5 | game:GetService( "ReplicatedStorage" ).DamagePlayer:FireServer(victim) |
I'm sure (and if you can't, I'm scared) you can understand the problem here. A hacker can just run this.
2 | for _,player in pairs (game:GetService( "Players" ):GetPlayers()) do |
3 | game:GetService( "ReplicatedStorage" ).DamagePlayer:FireServer(player) |
Oh my. What's the solution? Sadly, we must accept the latency. Players might complain about lag in your game, but tell them it's better than having hackers being able to kill everyone.
I hope this helps you with securing your game. Remember the three golden rules when developing RemoteEvents, and hopefully you'll be fine.