A (somewhat) novel approach to anti-exploits in Roblox (Repost)

A (somewhat) novel approach to anti-exploits in Roblox

The problem

One of the great problems in Roblox development is exploitation. The best way to prevent this is through a well scripted server, but some of these exploits, like clipping, increased speed, and flying cannot be stopped by just verifying that your game logic is sound. In order to stop those exploits you need expensive checks on every single player .

For example, an anti-exploit for increased speed has to check the player’s velocity/displacement every several frames (on the server), making sure that it does not go past the allotted speed (taking latency into account makes this more complex but still follows the same idea). Although this works well for one player, as more players join its begins to lag. This method is not scalable .

A possible solution

The basis

A way to scale the anti-exploit checks is to use the client’s computing power. Before you yell about the client not being able to be trusted, hear me out. Although a single client cannot be trusted, the majority of clients playing on a server can. This is the basis of cryptocurrency (kind of) so it is not a new idea.

The details

The proposed idea is to have each client performing checks on random peer players. Every n seconds the client would switch which player it was checking. Together the clients are continually checking each other.

If the checks are not passed for a specific player, a client can send a “tip” to the server. The server would then exploit check the suspected player and either determine they were exploiting or find out the “tip” was a false positive.

The server would also throttle the amount of “tips” a client can send, to prevent against exploiters trying to lag the system.

Why it works

Even though this system uses the clients to perform anti-cheats, it is secure. The server always has the final say on whether a client is exploiting or not. Also, even if someone deletes the script that scans for exploiters on their client, there are still plenty of other players searching.

When/where it wouldn’t work

This method does not work and/or is more weak in servers with few players. It also only solves the problem of scaling anti-exploits. Writing the exploit checks is a whole other beast.

Flexibilities

A lot of the details of this system are up for variation. For example, one could make it so that the client spends a variable amount of resources scanning for cheaters (a phone would do much less than a PC for example). Other changes could be what anti-exploit script is running or the system for choosing which player the client will check.

Disclaimer

This is not the best way to detect all exploits. Most can be stopped with simple sanity checks and sound server logic. This system is specifically for running expensive anti-cheats on things that are replicated to all clients (player movement, kills a certain player has, etc).

Tl;dr

In Roblox (and online games in general) certain exploits like flying and increased speed are impossible to detect unless expensive checks are performed on the server. This is not scalable and causes lag as the number of players increase. Moving these checks to the clients en masse creates a trustworthy network that can tip off the server when a player is cheating. The server can then monitor and kick those players that could possibly be cheating, continuing to act as the assertive authority.

Thank you for reading. Hope you have a good holiday season. :slightly_smiling_face:

22 Likes

I’m not entirely sure about the performance impact on such a widespread type of anti-cheat, but this sounds like it could work.

But, then again, wouldn’t the server have to store where each player WAS to verify the tip-offs it gets from clients? What about the performance implications of that?

The server could start storing and analyzing someone’s data after multiple exploit reports from that player have been sent from the clients.

Considering that clients will only be doing these checks each amount of seconds and most of them, will not even give positive, maybe this solution is not that performance-heavy? Calculations may also change depending on the player’s device, or maybe a custom checkbox that players could select to optionally send larger packets of data? With the future approach of parallel lua, tiny checks like these should not affect performance, not at all.

This honestly seems like a cool way of fighting cheats, just as cryptocurrencies do, that’s why most people say they are the perfect non-regulated currencies. Although this system will probably have a bunch of flaws and complications during the run, I may try to look onto this in my future project.

2 Likes

Anti exploits that rely on LocalScript can be easily stopped as cheaters have access to the client side and so they can delete them.

You probably didn’t read the whole post, but the thing of this anti-exploit is relying on all the clients, unless your whole community cheats, this could work. FYI, clients don’t have access to other clients’ local scripts, just to their ones. Even if a cheater deletes its own local script, the cheater will have no way to delete others.

2 Likes

Ok, they probably won’t affect performance, but to be honest, I still don’t understand how the usual server-sided checks affect performance anyway. I even ran a test with a script calculating the distance between the positions of 1000 randomized points, and then getting the size of the distance, and at max it took 0.6 milliseconds, but most of the time took 0.2.

local RunService = game:GetService("RunService")

local Points = {}

local Failed = 0

local function GeneratePoints()
	for Index = 0, 1000 do
		Points[Index] = Vector3.new(
			math.random(-1000, 1000) + (math.random(-100, 100) / 100),
			math.random(-1000, 1000) + (math.random(-100, 100) / 100),
			math.random(-1000, 1000) + (math.random(-100, 100) / 100)
		)
	end
end

RunService.Heartbeat:Connect(function()
	local Start = tick()
	
	GeneratePoints()
	
	for Index, Point in pairs(Points) do
		local LastPoint = Points[Index + 1] or Points[1]
		
		local Distance = (Point - LastPoint).Magnitude
		
		if Distance > 20 then
			Failed += 1
		end
	end
	
	print(tick() - Start)
end)

I already though to something like this, It would work like a blockchain, each player check another
And if one is detected as sus from 2-3 others plr then bann

You’re right. This system probably is more work to set up than the performance it saves for a simple anti-exploits.

The strength of the system is more useful when the anti-exploits become more complex and expensive. In the case of your example, adding checks to make sure that the points aren’t clipping through parts or are floating in the air would add more time. The system also frees you from having to give up security for performance.

Saying that the system used ideas from crypto was somewhat confusing. Let me clarify. This system does not use blockchain, is not decentralized, and only has the server as the one with authority to deem a client an exploiter. The only principle from crypto it uses is that although one client cannot be trusted, the majority of clients can. Adding a blockchain would only add unnecessary complexity in games with a server-client system (all Roblox games).