Check if RemoteEvent is called from a specific script

How would I go about having this RemoteEvent only fire if it’s coming from a specific script? I’m trying to find a way to secure it to try and prevent exploiters from injecting scripts and firing the event.

This is in a LocalScript

button.Activated:Connect(function()
	if cashAmount.Value > 0 then
		cashValueChanged:FireServer()
	else
		print("no more cash available")
		return
	end

This is in a ServerScript

local cashValueChanged = game.ReplicatedStorage.cashValueChanged

cashValueChanged.OnServerEvent:Connect(function(player)
	player.cashFolder[currencyName].Value = player.cashFolder[currencyName].Value - 10
end)

I think you can use the traceback feature in the debug library to see if it has a match for the script’s name.

You can’t exactly do that.
image

function d()
	print(debug.traceback(), "1")
end
game:GetService("ReplicatedStorage").testreplication.OnServerEvent:Connect(function(Player,Child)
	d()
	print(debug.traceback())
	print(debug.traceback(tostring(game:GetService("ReplicatedStorage").testreplication.OnServerEvent:Connect(function() end)), 10))
print(debug.traceback(tostring(game:GetService("ReplicatedStorage").testreplication.OnServerEvent), 10))
end)
1 Like

Try passing in the script’s name as an argument when you fire the event and then in the server script check whether the script’s name is equal to the name of the desired script, and if it is equal then run the rest otherwise don’t.

Tuples

In your LocalScript

local character = game.Players.LocalPlayer.Character

button.Activated:Connect(function()
	if cashAmount.Value > 0 then	cashValueChanged:FireServer(character, script.Name)
	else
		print("no more cash available")
		return
	end

In your ServerScript

local cashValueChanged = game.ReplicatedStorage.cashValueChanged

cashValueChanged.OnServerEvent:Connect(function(character, scriptName)
if scriptName == “LocalScript” then -- Change accordingly
character.cashFolder[currencyName].Value = character.cashFolder[currencyName].Value - 10
end
end)

Tuples are arguments that can pass through functions.
In this occasion, the LocalScript will fire the function and pass an argument containing the name of the script that fired it. The ServerScript will then connect that function when the event is fired, and require the script.Name argument that we made (with the variable of scriptName).
It will then make an if statement that checks the script name, and BOOM it should work.

Hope this helps!

2 Likes

Edit, you can actually do this, but it can be spoofed easily.

While this is better than nothing, it seems to be easy to fake

image

I can just put this in the command bar and it’ll still go through

I see. I haven’t ever worked with spoof security, and this might provide insight for a currency system I actually planned on making.

I searched some things up, and found this. It is a unique identifier service that generates an ID the script requires.

My idea is to generate an ID that the script would require inside the argument. It can go something like this:

In your LocalScript

local character = game.Players.LocalPlayer.Character
local id = “0” -- Change to whatever you prefer

button.Activated:Connect(function()
	if cashAmount.Value > 0 then		cashValueChanged:FireServer(character, script.Name, id)
	else
		print("no more cash available")
		return
	end

In your ServerScript

local cashValueChanged = game.ReplicatedStorage.cashValueChanged

cashValueChanged.OnServerEvent:Connect(function(character, scriptName, id)
if scriptName == “LocalScript” then -- Change accordingly
if id == “0” then -- Change accordingly
character.cashFolder[currencyName].Value = character.cashFolder[currencyName].Value - 10
end
end
end)

There is the inconvenience of having to change the ID manually if some random person is EXTREMELY adamant about spoofing money, but requiring both the id and the scriptName arguments should give enough security to prevent spoofing.

Hope this helps!

You shouldn’t do this, because if someone is using a remote spy (like how someone would usually find vulnerabilities), they will be able to see what arguments to send so that they don’t trigger your “anticheat” (and that includes any special identification or countermeasures you send in that remote event)

I looked some stuff up, and I think you should check out these resources:

  • This forum post helped me understand how to do sanity checks inside of scripts.
  • This YouTube video showed me what exploits are capable of, and exactly what to watch out for.
  • This Wikipedia article talks about defensive programming as a whole, and dives deep into the common practices and strategies most developers use to prevent exploiters.

In this case, sanity checks are necessary to secure the remote event, and the more parameters you add, the better security you will have against exploiters. In our case (and many others) we can use our current setting to our advantage. Think about it:

Firstly, a customer enters. Then, when buying items, the customer is usually in front of the cashier.

It’s no surprise that both of these can be passed as arguments from the client, but the real deal comes from the server too. Our next iteration can go something like this:

LocalScript

local player = game.Players.LocalPlayer

local shopRange = (player.Character.HumanoidRootPart.Position - game:GetService(“Workspace”).ShopPart.Position).Magnitude -- Change accordingly
local shopCheck = player.Character:FindFirstChild(“InShop”) -- Change accordingly
if shopRange <= 8 and shopCheck then
	if cashAmount.Value > 0 then
		cashValueChanged:FireServer()
	else
		print("Invalid Transaction")
	return end
end

ServerScript

local cashValueChanged = game.ReplicatedStorage.cashValueChanged

cashValueChanged.OnServerEvent:Connect(function(player)
local shopRange = (player.Character.HumanoidRootPart.Position - game:GetService(“Workspace”).ShopPart.Position).Magnitude -- Change accordingly
local shopCheck = player.Character:FindFirstChild(“InShop”) -- Change accordingly

if shopRange <= 8 and shopCheck then
	player.cashFolder[currencyName].Value = player.cashFolder[currencyName].Value - 10
end)
else
print(“Malicious behavior detected.”)
-- This wouldn’t fire unless an exploiter bypassed the LocalScript first.
end

This won’t prevent ALL exploits, because it isn’t possible. This only makes it so that exploiters can’t spend their money outside of the shop, which in this situation prevents all exploits. Cool.
With that being said, there is no happy go lucky, all around, easy peasy way to prevent exploits. I thought there was, but looking stuff up had me realize it wasn’t what I originally thought. We learn and we grow I guess.

Basically, just think about what you want the average player to do inside your functionality, and make unnecessary boundaries to make sure exploiters have a harder time breaking it. And don’t trust the client, because exploiters have full control over everything client-side.

I hope this helps!