How Can I Generate A Random Code?

This method of securing your remotes is easily bypassed and can be exploited because at some point you need to send the code to the client for them to send it back to the server. Exploiters can see all remote traffic passing in and out of their client so it is just a question of the exploiter finding the code somewhere on their client. Once the exploiter has the code they can easily fire any remote they want by just attaching the code they found as one of the arguments.

The best way of securing your remotes is by applying the appropriate server sided validations and checks, assuming that everything passed to the server has been tampered with. Lets say a player is requesting for their money to be increased you should do the appropriate checks to see if they are even allowed to increase their money before increasing their money.


As for your question it may be easier to generate a random number instead of a string of random letters and numbers because in this circumstance it wont make much difference whether it is a string or a number. You could use math.random() to do this. E.g: math.random(1000, 100000) will generate a random number between 1000 and 100000.

I haven’t tested it but unless I’m missing something this won’t work? You’re getting the __len of the table ‘MetaTable’ while indexing itself in that table? Your table is just an array of numbers, this wouldn’t work - it’ll likely return ‘attempt to get len of nil value’ as an error

So there’s two things to unpack here:

This isn’t good practice. To do this effectively, you need to generate the same sequence of random codes on the server and the client. This means that both the server and client need to store a state value. An exploit can easily get the state of your random function and bypass your security check.
It’s useful for throwing off the generic exploiter that just knows how to run a script someone else wrote, but anyone worth their salt won’t be stopped by this if they really want to send remotes in your game.

This is even easier if the code is static and doesn’t change while the game is running. You’ll want to check your RemoteEvents on the server and make sure the data they’re receiving isn’t some exploiters’ junk data.

This only works if the server is generating codes. If the client and server need to independently generate their codes, you’d want to use two Random objects initialized to the same value.

On the client:

local randomObj = Random.new(1234)

function sendRemote(...)
	remoteEvent:FireServer(randomObj:NextInteger(), ...)
end

On the server:

local randoms = {}
local players = game:GetService("Players")

players.PlayerAdded:connect(function(player)
	randoms[player] = Random.new(1234) --Same seed as on the client
end)

players.PlayerRemoving(function(player)
	randoms[player] = nil --Cleanup
end)

remoteEvent.OnServerEvent:connect(function(player, key, ...)
	local randomObj = randoms[player]

	--Verify client key
	if (randomObj == nil or randomObj:NextInteger() ~= key) then 
		player:Kick("Something went wrong!") 
		return 
	end

	--Your server code here
end)

Once again, this is bad practice and you shouldn’t be relying on this for security.

My example script would return a random number in between 1 - 3.

It would need to be:

math.randomseed(tick())
local MetaTable = {1, 2, 3}
local Key = math.random(1, #MetaTable)

Your example indexes the MetaTable with itself, which would throw an error as it’s not defined, and I’m unsure you can do cyclical references

The numbers I put were just as an example he could put as many keys (Including letters and numbers.) as he wanted into the table and it would work. The way you did would only work with numbers and not a random passcode.

It would work with letters:

local hash = ('a,b,c,d,e,1,2,3,4,5'):split ','

local function generatePoorPassword(length)
	local pw = ''

	for i = 1, length do
		math.randomseed(tick())
		local k = math.random(1, #hash)
		pw = pw .. hash[k]
	end
	
	return pw
end

print(
	generatePoorPassword(5) --> 4d335
)

I’m not trying to one up you btw, this is Scripting Support - we’re meant to work together to help the OP. I’m just pointing out a flaw in the example so that the OP doesn’t get confused further :slight_smile:

The issue with your initial code:

People can just intercept the firing of the RemoteEvent and change the arguments.

2 Likes

Your way would work too I’m just saying my way would generate a random number between 1 and the number of keys in the table and then it would index it to get a random key.

Exploiters can decompile LocalScripts’ source into readable format and easily discover whatever key or keys you’re using, it’ll only take a bit longer for them to ‘exploit’.

Regardless, your best option would be to in some way sync a random identifier between the server and client and immediately change it each time you fire a remote, but this is still generally not a good idea to rely upon.


Several tutorials and resources exist on the internet to explain metatables.

I made this a while ago:


    local function randomWord(len, unique)
    if unique then len = math.clamp(len, 0, 26) end

    local letters = {}

	      for byte = 97, 122 do
	      table.insert(letters, string.char(byte))
	      end

    local str = ""
    local count = 0

    repeat
          count = count + 1
          local rand = Random.new():NextInteger(1, #letters)
          if unique then
          if not string.find(str, letters[rand]) then
          str = str.. letters[rand]  
       end
   else
          str = str..letters[rand]
       end
    

    until #str == len
    
    return str
 end

 print(randomWord(3, false))

This will not work, exploiters can just rip the code from your localscripts

You can’t know what the code is if a server script is generating it.

Exploiters can see the arguments passed through RemoteEvent::FireServer so trying to secure the client like this is pointless. “Passwording” your remotes is security through obscurity which I argue is not true security.

The code is useless if the localscripts don’t have them. And if localscripts can get them then an exploiter can get them. An exploiter can basically pretend to be a localscript.

Sidenote on why this isn’t completely useless

@ScriptideALT @sjr04
An important point to make here: It’s not completely useless. Adding a code where exploiters have to read a remote event requires more work. Inexperienced exploiters (which make up a good majority) won’t be able to bypass it. While it can be bypassed, it still is useful. It shouldn’t be your main defense, but it can still be a good one.

A good analogy is it’s like a brick wall. With the right equipment, it can be broken. But, if you don’t have the tools, it’s a good defense.

The code OP wants

Here’s some simple code that should achieve what you want

local chars = "ABCEDFGHIJKLMNOPQRSTUVWYZabcdefghijklmnopqrstuvwxyz1234567890"
--The characters that can be used in the code. You can add symbols too if you want.

local function getCode(length)
	local code = ""
	for i = 1, length do
		local randNum = math.random(1, chars:len())
		code = code .. chars:sub(randNum, randNum)
	end
	return code
end

print(getCode(5))
print(getCode(15))
print(getCode(3))
Example output

image

Hope this helps. If you have any questions, feel free to ask.

6 Likes

This is true, it is better than nothing. However an even better “code” is to just check if the remote is valid just like you would check if the code is valid.

Also, if you are doing codes, make sure to generate only one at the start of the game. If you generate one each time it will increase latency

Of course. In all instances, the best security is to check if the request is valid. A player can’t spend 500 cash if they only have 5. You can’t spawn the best car in the game when you don’t own it.

The point is I think the OP wants a one size fits all solution, which isn’t really secure in the first place.


@ScriptideALT
Generating a code really isn’t that intensive.

A good defense shouldn’t be dependent on whether exploiters have the ‘tools’ or knowhow on how to exploit your game. Regardless, if a client is able to fire a RemoteEvent, that would mean they know (1) the function to fire, (2) the remote event to fire and (3) the arguments used i.e. the code. This reveals that it is, in fact, truly useless.

The better defense is to sanity check all input both locally and on the server.

Let’s imagine we’ve given our user a gun, and we’ve told the local machine that it can fire n bullets per second. Locally, we would only fire the event at the defined speed. If an exploiter wished to increase that fire rate, they would need to fire the event at a higher frequency. On the server, you could track each call by every client, and if it is greater than the defined limit for the gun they are meant to be using, it can ignore the call or remove the player from the game if this occurs too often.

What?

I said it was a good defense if you don’t have the right tools. Most exploits can execute code, like firing remote events. Not all of them can get incoming and outgoing traffic. Most exploiters end up copying and pasting code, so you end up blocking a good majority of exploiters. From what I’ve seen in my games, a good deal of exploiters fail this simple trick.

Yes, the better defense is always sanity checks. However, the OP wants a solution for all remote events (which really isn’t possible, hence this conversation), which there is no real secure solution for.

1 Like

Real quick… what is this security model.

Remote events exist and can be fired at will. It’s up to the developer’s server implementation to decide if that remote firing is valid. In this case it seems to be validated with a random string.

What’s been provided is a truly random generator instead of a pseudo-random generator. So either the server or client uses the function; but it can’t be both.

In the case that the client is generating the random string, it’s not secure. It’s just a random string that the server has never seen before and cannot validate.

But if the server generates the string and sends it to client for its next remoteEvent use then that’s better. Now an exploiter must intercept the random string to be able to fire any valid remote event. But then the defense stops, if the exploiter learns what to look for or if the random string isn’t immediately replaced after usage; the entire system is vulnerable.

In my opinion, its a similar reasoning that because a website only interacts over TLS connections, then its not vulnerable to cross-site request forgery or cross-site scripting attacks. The model should treat potential attackers no differently than the client. So I wouldn’t say its good practice to let the client validate itself.

But I appreciate both sides of this argument; because both are right and the exploiter is required to adjust. Just wanted to point out how the server-client model relates to this.

2 Likes