I am currently working on a website that gives people a suite of tools to help sell their stuff to games. One of these tools is the ability to safely protect the source of scripts.
I need to create a whitelist system so that only certain games can use peoples products, but I need to make it so that someone can’t just take the bytecode that sent to the game and make the script think our server says the game owns it.
I know that a whitelist system shouldn’t just have a yes or no response, but I don’t know how I could integrate a completely random response in so that it is required for the script to actually function. Not just some if statement, but have the response deeply integrate into the script so that, without it, the script actually won’t work. But it’s not that easy because I need to make it so someone can’t just use the same response again.
You might have the script check a server-given cryptographic signature against a combination of a timestamp, some identifier of itself (like a name), and some random number provided by the script. If the time-stamp is not recent or the cryptographic signature fails the check, don’t run the script.
This would make it much harder to fake a response, though what’s to stop someone from faking an old “os.time” or a specific “math.random” response from a sandbox?
Eh. Who cares? It’ll make exploiting sandboxes as workarounds much more of a nightmare.
There’s no way to escape a sandbox (such as a full VM) once a script is put into one. A script could be running inside a reimplementation of the Roblox engine for all it knows. The only thing you can do is make it as much of a nightmare to workaround the restrictions as possible. For example, by accessing a bunch of seemingly-random APIs at random points in a script and verifying that they behave as expected.
Try looking at how history repeated itself with DRM (Digital Rights Management). Usually, when a developer protects its games with DRM, some bored computer guru later breaks/works-around the DRM.
This is what I’ve also been struggling with. One of the ideas that I had was the following:
Vital script’s constants are stored on the server
The script makes a request and retrieves the constants in an encrypted form (if auth succeeds). The encryption key is random every time
The script can figure out the decryption key from the response, which only it knows how to do
What I also ended up implementing as an addition was encrypting the entire response mentioned above with a static key. The only way for the script to figure out the key is make another request to the server asking for the seed for math.randomseed, which it then uses to generate a random string of a fixed length, which is (you guessed it) the static key!
(Said request also requires 2 parameters which are supposed to prevent replay-attacks but I don’t want to get too deep into that)
Anyways let me know what you think of those ideas. It was the first time doing such a thing for me when I made them so they might not be perfect.
If you’re working with seeds, would the Random API help you out here? Seeds to a Random are local to the object while math.randomseed affects all math.random operations and other scripts could be making use of randomseed.