Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Remotes don't utilize callbacks to enhance security?

Asked by 5 years ago
Edited 5 years ago

I cannot think of a reason why ROBLOX has not implemented something like this. To me, it adds the option to enhance security immensely. This is more of a why not kind of question.

Details

To be more specific: for remotes, why doesn't ROBLOX check for some callback function to execute before sending data over the network?

It seems to me that you could easily filter out when a remote is supposed to be fired, and when it is not, if they just granted us the option to run some code before the remote actually sends anything. For example, say the FireServer method behaved something like this internally:

function Remote:FireServer(...)
    local validInvocation
    if self.OnRemoteFired then
        validInvocation = self.OnRemoteFired(...)
        if not validInvocation then
            return -- discontinue
        end
    end
    -- valid invocation; function may proceed to update the server
    sendDataToServer(...)
end

This way, we could just wrap FireServer inside a new function which uses some debounce gate that allows FireServer to actually send data if the gate lets it through. If the callback returns false or nil, then the call to FireServer is negated. Otherwise, proceed normally. Here's a practical example of what I'm talking about if such a callback existed:

-- debounce state in which data can be sent over the network
-- true: data can be sent
-- false: data cannot be sent
local networkSendState = false

-- set callback function
-- if networkSendState is true, the callback will return true, which in turn will allow FireServer to proceed normally.
function Remote.OnRemoteFired(...)
    return networkSendState
end

-- wrapped version of FireServer created by the developer
local function NewFireServer(remote, ...)
    networkSendState = true -- open gate
    remote:FireServer(...) -- send data over network
    networkSendState = false -- close gate
end

Now the client can tell if the call to FireServer was legitimate or not depending on the networkSendState. You, as the developer, now only use NewFireServer so that you have complete control over the gate, allowing you to pass through.

More Practical Examples

Suppose a developer now wants to catch an exploiter firing a remote

Developer's Code

function Remote.OnRemoteFired(...)
    if not networkSendState then
        print("Invalid FireServer invocation! Possible exploiter!")
        return
    else
        print("Valid invocation to FireServer")
    end
    return true
end

NewFireServer( ... ) -- opens gate to send "..."

Valid invocation to FireServer

Exploiter's Code

Remote:FireServer( ... ) -- gate was not opened, will not send "..."

Invalid FireServer invocation! Possible exploiter!

Easy, right?

Conclusion?

I need someone who's smarter than me on this one. Would this actually add a significant layer of security to network communication among ROBLOX games, or am I completely missing something and it creates more problems than solutions? Any input on this would be fantastic, as I've pondered this simple thought for a while.

Edit in Response to: Kiriot22

You brought up a valid point about overwriting OnRemoteFired, but couldn't that easily be fixed as well?

local Remote = {}
local Remote_mt = {}

function Remote_mt:__newindex(k, v)
    if self[k] and k == "OnRemoteFired" then
        return
    end
end

setmetatable(Remote, Remote_mt)
0
Then the exploiter could proxy the FireServer and send their own data instead of the passed one, or change the value of networkSendState variable to true, or even replace Remote.OnRemoteFired with their own function Amiaa16 3227 — 5y
0
They wouldn't have access to locals though, including NewFireServer and networkSendState. Also, you could just lock the callback once it's set, so you can't overwrite it, correct? UnitVector 47 — 5y
0
They can get access to the locals i.e. with debug.getupvalues(). And you cannot lock a callback in roblox. Amiaa16 3227 — 5y
0
Well, not locking the callback, that's a function. I'm talking about using the __newindex field. I updated my question to provide an example. UnitVector 47 — 5y

1 answer

Log in to vote
1
Answered by
Amiaa16 3227 Moderation Voter Community Moderator
5 years ago
Edited 5 years ago

Response to your edit.

You cannot just assume they don't have access to the debug library.

Now, in your previous code samples I thought the Remote variable is a RemoteEvent instance and not a table? And now you're saying it's a table.

But even if it was a table, you can still bypass __newindex by using rawset() or even debug.getmetatable().

Here's a code that an exploiter could use to bypass your check, if remote callbacks were a thing:

for i,v in pairs(debug.getregistry()) do
    if type(v) == "function" and debug.getupvalues(v).Remote then
        rawset(debug.getupvalues(v).Remote, "OnRemoteFired", newcclosure(function()
            return true
        end))
        break
    end
end
0
Instances and tables are the same thing functionally. getmetatable(workspace) returns the __metatable field set by ROBLOX. "Remote" is assumed to be a RemoteEvent, the table is the API. UnitVector 47 — 5y
0
Yes, except roblox Instances are userdatas, so they can use __namecall, and you wouldn't be able to override one's __newindex, because as you mentioned ,its metatable is locked. Amiaa16 3227 — 5y
0
Yeah, I just used a table for sake of simplicity, just as a proof of concept. I didn't know they would have access to ROBLOX's unmodded version of Lua 5.1 though? UnitVector 47 — 5y
0
I'm pretty uneducated about the power of executing code on the client I guess. Thanks for the info! UnitVector 47 — 5y
View all comments (2 more)
0
Well, script executors such as Synapse, Elysian or Protosmasher have implemented the debug library. Amiaa16 3227 — 5y
0
No problem lol Amiaa16 3227 — 5y
Ad

Answer this question