Except it doesn’t apply here. If you are letting the client tell the server what to loadstring (and you aren’t making a script builder or such), then there is something seriously wrong with your code.
On the other hand, if you know exactly what you’re doing, you will never “open up an opportunity for an attack”.
It does apply. This is why it becomes such a big vulnerability even in the professional world. For instance, imagine you need to run loadstring
, but you need to inject a few parameters. That’s easy, as you can just concatenate the string before loadstringing it. However, what if those parameters are coming from user input? If that’s the case, you have an exploitable system for the end-user to inject code.
For instance, maybe you have an input that allows the user to choose their name for an RPG. When you do that, the system runs loadstring on some code that uses the name to print it out (or whatever):
function AcceptName(name)
local code = loadstring("print('Hello ' .. name .. '!')")
code()
end
Now if the name
argument originates from user input, the user has the power to inject any code:
AcceptName("Bob') DoSomethingMaliciousHere() print(")
Which would resolve in the code:
print('Hello Bob') DoSomethingMaliciousHere() print('!')
The point is this: many younger devs will probably overlook small things like this. It happens in JS all the time, and it can happen in Lua too. Now, I am aware that this is more akin to SQL Injection, as XSS typically involves another client executing the code, but the concept is the same: allowing arbitrary code to be executed that might have been manipulated by an end-user.
This is exactly my point.
XSS vulnerabilities usually require the client to mess with the parameters it passes to the server. However in the roblox world, you should not let any player pass any arguments for your loadstring. If you do that, then it’s your fault if the game gets exploited, not loadstring’s.
In real world, I can’t think of any scenario where your game would need to loadstring anything a client sends, unless it’s a scripting game, in which case, sandbox is a must be.
Ok so I think we’re actually on the same page here. My point is that many young devs don’t realize they should avoid doing that, which is why it’s better to just avoid using loadstring
But loadstring is basically recompiling (one of the heaviest tasks Lua does) which can have a performance penalty if used a lot.
Compilation itself is slow and still a lot faster than other languages, but once compiled, it runs at the same speed as any other script. A lua-in-lua VM would definitely run slower.
Server-side scripts are never shared to the client, only replicated.
Please correct me if I am wrong, it is not been long since I became a new member.
Yep, the objects replicate (if the Script object is in a place that should replicate), but the bytecode does not. It’ll just be an empty container on the client.
Be careful with ModuleScripts that contain code that is normally only executed by the server, as the bytecode of ModuleScript source will be sent because the game doesn’t know who will be executing that code, so it has to be made available on the client too. It’s good practice to keep all your server-only stuff in ServerScriptService / ServerStorage for this reason.
I’ve been doing some research on game security recently. You are correct that it is a complicated subject.There are several methods for securing a game, but one of the most crucial is maintaining the integrity of your data. It’s critical to keep your data safe because it’s what keeps users engaged in your game. The most common way to do this is to ensure that your game is not susceptible to cheating. When gamers utilise tools to obtain an edge over other players, this is referred to as cheating. There are other methods to cheat, but I’m mostly referring to aimbots. It is also possible to cheat by getting an unfair edge during games. Unfair gaming occurs when players take advantage of game faults or mistakes to obtain an edge. Cheating is also feasible through the use of exploits or cheat codes. Cheat codes are essentially hidden codes that provide gamers with an advantage over other players. It’s critical to keep your game safe since it keeps it alive. If you want to keep your game alive, you must ensure that it is bug-free. A “bug” is a flaw in a game that allows players to gain an edge over their opponents. It is critical to safeguard your game since it keeps gamers engaged in it.
In the AcceptName() function can’t you just do a sanity check to check if the user input does not contain (") or (’)?
function AcceptName(name)
if string.find(name, '"') or string.find(name, "'") then return end -- my addition
local code = loadstring("print('Hello ' .. name .. '!')")
code()
end
Now no client can inject code in this case.
That solution doesn’t scale.
-
You would have to apply this on every client input consumer. An exception case can be made for a module that supports middleware and if all communication is filtered through it.
-
You may want to accept quotation marks in your client input consumer. Blocking against quotation marks therefore wouldn’t make sense in that scenario.
-
Quotation marks aren’t representative of a code snippet. The whole problem relies around bad design allowing clients to pass anything executable.
The case I made when this thread was created was that LoadStringEnabled does not immediately put your experience’s security at risk. The discussion they were having is that careless or bad design can lead to a client being able to leverage server loadstring permissions and have it execute code.
The only foolproof solution against a client tricking the server into executing code is good design or not having it enabled. Beyond that, other proposals such as checking for quotations in input bank on assumptions about the incoming data.