I want to make a plugin to access my github, but to use it the user has to switch on HttpEnabled in order to make web requests. Since the sole purpose of my plugin relies on that connectivity it would be nice to not have to ask them to switch it on to use my plugin and instead just allow requests from Plugins automatically.
It should not be tied to HttpEnabled I agree, and maybe the user has to approve Http access for each plugin individually? For example this could help against shady plugins that are gathering information about you or your games without you knowing.
That could be potentially bad, because I could easily just send the entire place to an eternal server and steal any number of peoples games before the plugin got found out.
I like the suggestion of per plugin HTTP access, though. That might be better.
Maybe there could be a permission system like how mobile apps and chrome extensions work.
Itās not really different in the current system anyway. If you open a game that already has it switched on then youāve just allowed that user to send the place to their server. Itās down to the user to select the plugins they use and if their are some shady ones then perhaps itās their fault for choosing it?
That sort of argument will never slide with ROBLOX, though, as evidenced by us not having clipboard support.
Ideally we would have a robust permissions system where you can grant the ability to make HTTP requests to certain plugins and not to others. Unfortunately our system was not designed this way. When you click play in Studio any script can make an HTTP request, so if we tried to impose restrictions when plugins make HTTP requests, we would also have to build a permission system for scripts as well.
The best short-term solution I can think of would be to prompt the user whenever an HTTP request is made to a new domain (e.g. www.example.com) and give them the option of allowing/blocking all requests from that domain. This would ensure that if you insert a script into your game which tries to steal your place, you would notice a suspicious domain and be able to reject the request. We might even be able to remove the HttpService setting if we did this.
If weāre being honest here, Iād prefer it if scripts had a permissions system, as itād effectively eliminate plugins and normal scripts as a method for sending data without permission.
If you have suggestions on specifically how a permissions system could be implemented in the ROBLOX engine, please post them here. We are open to ideas.
WARNING: Wall of Text Ahead
After talking it over with friend, there are a few ways that a permissions system could be reliably implemented:
If weāre talking plugins, itād be as āsimpleā as adding a prompt when installing a plugin to allow access to certain APIs (Http, Datastore, Create place, that sort of thing). Thatād presumably be stored either online or in the same folder as the settings.json for each plugin. This would let plugin owners not have to have their plugin whitelisted every time it updates, as well as give the user control over what they can do.
When we get to regular scripts, it gets a bit more complicated. You can obviously try to just have a list of properties per script that allow certain things to be done in it, but that raises some annoying problems. For starters, itād have to take into account both pre-existing scripts, scripts inserted via plugins/models, and scripts created during run-time. These properties would have to have some form of security on them (either one of the thread identity tags or unscriptable), and be set automatically in some cases to avoid being annoying while making scripts. Ideally, if this were the way things were, theyād be set automatically when a user inserted a script themselves (via Advanced Objects or the like), and if they were inserted in studio from Free Models, Insert Service, or a Plugin, they would have to be manually set (via prompt or otherwise). As for scripts inserted during runtime, if it was inserted and in the developers inventory, it should inherit the permissions that it had while being published; otherwise, it should have no permissions. This system is a poor choice because it requires saving this sort of data per script, which is unnecessary, in addition to modifying scripts, ModuleScripts, the publishing system, and the inserting system.
Another system that could be implemented is similiar to the above but on a per-source basis. The idea would be that for every source in the game, it would have to be whitelisted in order to run certain members of the API. In practice however, this raises issues with plugins and free models. For plugins, their sources can be updated frequently, and this would require a re-whitelisting every single update (unless it was combined with the initial plugin suggestion, which is sound). For free models, it raises several issues. If youāre inserting something that relies upon a ModuleScript, does it just assume that ModuleScriptās permissions? What if that ModuleScript uses the HttpService or one of the other APIs that isnāt allowed in the initial script? If youāre requiring a module by ID, how do you confirm that that ID wonāt be doing malicious things later on? Thereās an argument for not caring, as even with the current system this could be put in place, but it may as well be brought up since weāre discussing this. Thereās no easy way to address this, which brings me to our third and most drastic/involved method.
Google Play and services like it implement permissions upon install of applications and programs. These permissions are given to the user for confirmation upon request to install. If this were applied to ROBLOX as it is in those systems, it would fail miserably simply due to ROBLOX being unable to determine the permissions of a script (possibly, Iām not sure if this is true), and not being able to trust malicious users to give the correct permissions. The solution, if something were to be implemented like this, would be for ROBLOX to auto-generate permissions per-script. How they would do this is really up to them, but CntKillMe (the friend I mentioned above) suggested a VM based check in order to determine what functions would be called were the script to fully run. His suggestion included running every line, ignoring line-skips, and catching if any blacklisted functions were called, then tagging a script with that permission. Iām by no means an expert on the Lua VM, so Iām not sure how viable that is to do in practice, but itād not be without its hardships. Provided it is possible, then the model would be tagged when it was published as either a plugin or an actual model and given permissions that could be prompted upon inserting. It would have to be done on ROBLOXās servers, to prevent client-tampering, but it would be the most reasonable solution.
There are two major flaws in the above system, one of which is present throughout all three suggestions. This is, of course, the ModuleScript problem. You cannot reasonably assume that ModuleScripts are safe, if theyāre required by ID. This means youād have to do one of three things: Inherit permissions, warn the user that theyāre using a ModuleScript they donāt own (would require a basic check on what was being called in a script), or do nothing. Inheriting permissions would be the easiest solution, but it falls apart because of how ModuleScripts are run: once per client/server, per identity. What is safe in one script may not be safe in another, so you cannot assume permissions. This leaves warning the user and doing nothing, of which one is obviously better than the other. Thereās another option, which is an extension of the first, which is to make ModuleScripts run per permissions, per client/server, per identity. Thatās obviously not ideal, so a warning would probably be for the best.
The second flaw is, well, a much harder one to solve. The problem with running a VM would be catching all the functions referenced. This is a problem that me and CntKillMe thought hard about, and couldnāt come up with a solution that wasnāt disgusting. By the very nature of Lua, there are literally infinite ways to reference and call a function, meaning there are literally infinite way to potentially bypass this catch. If it were run line by line, it would be very possible to set a variable to nil in a way that would only happen while the VM was running, ending in an unsafe script being tagged as āsafeā.
The two āgrossā methods we came up with are as follows:
1.) Run the entire script with every condition running as both true and false. This is disgusting because it would take forever, and is horribly inefficient.
2.) Run through the script and catch intentially hidden references somehow, whether it be through checking the previous contents of variables or something else.
(This assumes weāre using a VM, which may be a poor choice. Iām not an engineer, I donāt know whatās best for ROBLOX.)
EDIT: Might just be worth skipping over or flagging anything suspicious like āif false thenā or āif math.random() thenā and checking it thoroughly.
TL;DR: Thereās no easy way to implement a permissions system for ROBLOX, but there are quite a few ways to almost implement one.
Something along to lines of.
-- Returns a boolean as to whether the user has granted the plugin permission
plugin:GetPermission(string permissionFlag)
-- Prompts the user for permission to use a certain feature
plugin:RequestPermission(string permissionFlag)
-- Executes the callback function or errors if the relevant flag is false
plugin:InvokePermission(string permissionFlag, function callback)
or
-- plugin:InvokePermission(string permissionFlag, httpService.GetAsync, variables)
-- Permission flag tells you that you need to pass httpService in internally
-- so it's not one of the variables
plugin:InvokePermission(string permissionFlag, InstanceMethod method, variables)
If itās possible though the latter would be better if it didnāt require a callback and instead the plugins security would allow it to now use the method it has requested (such as those under HttpService)