Recently i’ve been into learning game security and how to prevent exploiters from hacking in your games.
And one of my biggest questions is how can we fully (or maybe?) “protect” RemoteEvents from exploiters. (Falsely firing events, RemoteSpy, etc.)
I have tried doing alot of things such as adding a type of password when calling/receiving the RemoteEvents and checking the last time an event was fired by a certain player, But turns out most of these methods can easily be bypassed.
What do you guys think about that? Is there a way to fully prevent exploiters from falsely firing events?
There is no protecting RemoteEvents. You won’t find a good and performant solution when it comes to stopping people from falsely firing events or using RemoteSpy.
Just make sure to do tons of sanity checks on the server and you should be fine.
There’s no way to protect a RemoteEvent being fired from Client to Server. But you can put checks in place to help prevent exploiters from being able to do whatever they’re trying to do. For example, if you have a command panel (GUI) that’s ONLY given to people you choose, and it fired a remote to a script in ServerScriptService, you could make sure the player’s user ID is the equivalent of who you permit to use said commands. Otherwise, kick the player for hacking.
What I do is I create a folder in ServerScriptService for every remote event, and whenever a player joins, I add a bool value to each folder (set to true on default) and whenever the remote event is fired, the bool value is set to false. A script detects the remote event changieand after a set delay, the bool is set to true again.
Whenever a player fires a remote event, the server checks to make sure the player’s bool value is true.
Might not work for everyone but this is how I do it.
So, I was put a small anti-remote-bypass system or something like that.
RemoteEvent is used for client-client, client-server communication.
So there are some ways to check if the argument (might be nil) is a known one.
Example:
There is a ShopGUI And gets activated with a RemoteEvent.
When ShopGUI gets activated, you can check if the player is at a valid activation position.
Ex 2:
A morph GUI, RemoteEvent has an argument named “morphname”. When it gets fired, you can check if the morphname is a valid.
Could you explain why you think my idea doesn’t protect me from anything? I’m pretty new with securing remote events and I would appreciate your feedback on this.
It won’t secure because it doesn’t have a point, also it might affect the performance too. As it doesn’t have a point, let’s make a point for it! So, yes, we use RemoteEvents but we have spammers (Ex: ShopGUI / Player is spamming the buy button.) and we need to prevent spamming. This is my method.
local PlayersThatFiredRemote = {}
local Remote = game.ReplicatedStorage.Remote
Remote.OnServerEvent:Connect(function(plr)
wait(0.5)
if table.find(PlayersThatFiredRemote,plr.UserId) then return
else
table.insert(PlayersThatFiredRemote,plr.UserId)
-- stuff here
wait(0.5)
table.remove(PlayersThatFiredRemote,plr.UserId)
end
end)
Since player can activate a remoteEvent when they want, your method won’t have a point. But I saw your method, transformed it to anti-spam remote system. And I don’t advice that method to you. I think you’ve tried to make an anti-spam but, it might affect the server. Because of this, I’ve transformed it, but it’s working with tables! I’m advicing you to work with something like that.
When trying to understand where an exploiter sits at in your game, it can be difficult, but it doesn’t need to be.
Do sanity checks!
Cannot stress this enough. If you’re making a system that is sort of like an admin GUI, make it so the client just fires the server (ofc add a denounce so their firing is rate limited) and the server receives the information, and checks your userid. That server script would have a table of userids that are allowed to use the gui, and the script will check the specific players UserId. If their UserId doesn’t exist in the table, the best thing to do is to kick the person who fired because no average player would be trying to fire hidden remotes and stuff.
Personally what I do that is a complete show stopper for any exploiter, is turning their own executor against them. This might sound stupid, but all executors don’t actually have names when they inject code.
An executor is basically just a local script that they manually fire, so what I do on the server is keep the name of my local script into account, and when I fire I check the name of the script that fired in their player scripts folder. That way if an exploiter tries to fake their scripts name (keep in mind executors script names are just “LocalScript” the client would have told different information from what the server sees so it won’t continue, since nothing client sided replicates to server boundary.
Then again…
There is no true way to stay safe from any form of exploit. Bypassing things can be easy, but when you have things like UserId checks and stuff that completely destroys any chance of any exploiter getting what they want out of you, you pretty much did a good job at that point. However, Userids don’t work for everything unless it’s restricted.
Ok, I’ve used this way to secure my remotes. I have made a passcode where it fires with the remote. For example, the code = 8323f8929gj92gv2g and then I make it do FireServer(remote,code). and when It gets the server function it makes it check if the code is equal to the code else It detects that a exploiter has tried breaching the remotes.
These are some of the things I do to make RemoteEvents more difficult for exploiters to make unintended use of.
I don’t publish my games with RemoteEvent instances in ReplicatedStorage, I have the server create them all at startup. I define all my remote events in a Lua table in a ModuleScript in ServerScriptService. This allows for some simple exploiter countermeasures I detail below.
All of my RemoteEvents are uni-directional. By this I mean that any particular RemoteEvent instance is only used for either Client-to-Server or Server-to-Client communication, never both. This is configured in the server-side Lua table, so that only the server knows a RemoteEvent’s direction. Then, on the server, all Server-to-Client RemoteEvents are connected to an OnServerEvent listener that is only used to detect exploiters. Anyone firing a RemoteEvent in the wrong direction gets kicked and banned, since it’s only possible to do this by exploiting. Exploiters love to just loop over ReplicatedStorage and rapid-fire all the remotes they find, hoping one of them does something to break the game. If you’re really nasty, you can include decoy events that your game doesn’t really use but have enticing names like “GrantCoinsEvent” or “KickPlayerEvent” and just bind them right to your exploit detection code.
All RemoteEvents are strictly validated. Number, type, numerical range and context of all RemoteEvent parameters are defined in my server-side table and are validated. I put context in bold because this is something a lot of developers don’t think about including. What I mean by this is validation of whether or not an incoming RemoteEvent is expected based on the state of the server. For example: an event that a player has fired their gun might only be valid during the gameplay round of a FPS, not during intermission when players are in the lobby. If your game server has a state machine, you can use this to define which states a RemoteEvent is valid for, where this makes sense.
RemoteEvents for admin commands are only replicated to players who have already been authenticated by the server as admins (by UserId). This is done by creating per-user RemoteEvents for each admin player and parenting them to their PlayerGui so that they only replicate to that player. LocalScripts that use these remotes are likewise provided only to these players. This way, exploiters don’t even know that admin UI and events exist, they never get them.
My RemoteEvents server table also has per-event rate limits. The server has thresholds and “leaky bucket” counters for each event. If someone is firing an event 10 times per second, and I know it’s something that a legitimate client will only send once per minute, I can flag it as exploiting. The leaky bucket approach prevents false positives due to packet timing irregularity.
I generally don’t bother with client-side obfuscation like having the server randomize the names of RemoteEvents and send the client a manifest (which is the effectively the same as generating passwords and then sharing them with the client). This complicates client code and won’t thwart determined exploiters, only slow them down a bit.
Yes, you will have more chances of a secure game if remotes will be fired at a certain time. You must also have it generate a random key with encryption every time the remote is going to be fired. Now if that doesn’t help you that way, you can use remote functions which get data from another side and return it back to your side. How is this helpful? You can have your encrypted code in the Main script where exploiters won’t have the power to do so and from the main script, It will return back to the client.