How do i make a sanity check for Remote Events / Functions

Building on @goldenstein64 answer, have you considered using a count when implementing sanity checks?

This enables a remove event/function to be called multiple times in a short period of time (e.g. if firing bullets from an automatic weapon) without triggering as many false positives or a lengthy cooldown.

For example:

--Variables
local requestsLimit = 20
local sanityChecks = {}

--Refresh Sanity Checks
coroutine.wrap(function()
	while wait(5) do
		sanityChecks = {}
	end
end)()

--Main
Remote.OnServerEvent:Connect(function(player,...)

	--Sanity Checks
	local remoteName = Remote.Name
	if not sanityChecks[player] then
		sanityChecks[player] = {}
	end
	local requests = sanityChecks[player][remoteName]
	if not requests then
		requests = 1
		sanityChecks[player][remoteName] = requests
	else
		sanityChecks[player][remoteName] = requests + 1
	end
	if requests > requestsLimit then
		--Warn user is making too many requests
		wait(1)
	end
	
	--Do your stuff
	
end)
3 Likes

This code is very well written and seems to get the job done really well. I like the idea of having a coroutine to handle refreshing of the debounces.

However, I would question if it’s a good idea to store the player object themself in the sanity array. Would it not be better to store player.UserId instead?

The only caveat with not using the player’s UserId is that if the sanity check table doesn’t refresh, then a reference to the player will be kept which will prevent their object from being garbage collected should they disconnect from the game. Otherwise, there’s no real difference between using it or not.

1 Like

The reason people kick the player is the same reason they ban them; to deter any future exploiting attempts and to remove them from the game. If your game is well thought out and well executed there shouldn’t be any incorrect parameters sent from the localscripts.

Manual moderation is different from embedding a kick function into your scripts for a failed sanity check, whether that’s a developer-made fault or one that’s generated from spoofed or wrong arguments. Manual moderation is a band-aid solution to “deter future exploiting attempts” which is only relevant to a single account. It’s not scalable or effective. The proper solution is to fix your game.

1 Like

I think it’s just as valid as any other vote to kick system since they are both checking for exploiters.

Regardless, I’m by no means saying that you should always kick people who failed sanity checks (do to false positives) however there are some situations where you can be 100% sure that a player is exploiting, and it requires immediate action. An example of this would be when phantom forces kicks you for fly hacking, or when jailbreak kicks you for no clip: both of these are situations where there is no room for false positives (the game is sure the player is hacking) and kicking the player is actually required. Anyways, I understand now that spoofed or incorrect arguments sent through remotes do not require immediate action or attention, and so ignoring the request instead of punishing the player is the correct choice in that scenario.

Vote kick is also a form of manual moderation, by community instead of by staff.

Kicking players for explicitly exploiting is fair in itself, if that’s the intended function of your script. I’m generalising my response towards sanity checks of remotes in general though.

If you’re not explicitly checking for those kinds of exploits with remotes or whatever and it’s simply a remote for client-server communication for some kind of game functionality, there’s no reason to kick a player - just reject the request or do nothing if the checks fail. If a player does get kicked for hitting a false positive or something that’s the fault of the developer, that’s dangerous for UX and it doesn’t really help anyone either. A simple request reject allows everyone to continue playing, even in error (not as in a script-terminating error though).

Anyway, that being said, feel free to hit my DMs if you’re interested in further discussion or anything. I think we’ve dragged this topic out a bit, lol.

1 Like

Hey, I know it’s been a year but it’s still a very important topic,

So how I do it is-

-- Server
local RemoteEvent = game.ReplicatedStorage["NAME HERE"]
RemoteEvent.OnServerEvent:Connect(function(client, argument1)
      if argument1 == 'ye this is it' then
            -- code here
      end
end)

-- Client

-- code here

game.ReplicatedStorage['name here']:FireServer('ye this is it')
1 Like

You have the right idea, but what you’ve currently ran into is a password-protected remote which is not real security. It could be a different story if your script actually needed to send a string though and the server needs to either validate or sanitise it.

If you’re validating a string for example and don’t want it to exceed a certain number of characters, you can check the length of the string using string.len or the length operator (#). Then after getting the number, check if its under a certain amount. If it is, then proceed with your code. If not, then end it there.

If you’re sanitising a string for example and don’t want it to exceed a certain number of characters, you would use string.sub in order to cut off excess, so that the server is only working with the first 200 characters of the string or so. You can then proceed using that sanitised string.

A personal favourite thing of mine with regards to sanity checks is guard clauses, so I can “detach” my checks from my code. So rather than an if statement encapsulating all my code, its just a line or some that act on the received arguments.

OnServerEvent:Connect(function (player, a)
    if #a > 200 then return end

    -- Code here
end)
3 Likes