Security implications of private or public functions with RPCs

Godot Version

4.6

Question

I’m quite new to using Godot with C# and I’m experimenting a bit. Anyhow, I was curious about this specific question that I couldn’t find much to any answers about and I thought I might ask here:

Should I be wary about using public or private functions with RPCs on Godot? As in, if it has any direct security implications. I’m assuming, since all functions (presumably also those with RPC calls?) on gdscript are public, it should be fine?

I apologize if the answer to this question is simple, I’d rather be safe than sorry when it comes to networking though.

1 Like

You are correct about Godot not having explicit public and private functions. However, that’s not actually related to RPCs and network security at all.

RPCs (Remote Procedure Calls) simply are a way to tell other machines over the network to either do something and/or send simple data like strings, bools, integers, etc.

For security, you really don’t have to worry. Just NEVER allow peers to send files over an RPC themselves. Which is called serialization.


Also, for RPC calls, there are a few arguments that determine which peer can call a function on another peer’s machine.

Firstly, Use your_function.rpc() to tell all other clients to perform a function.

Secondly, use your_function.rpc_id(client_id) to tell a specific client to perform a function. The client is marked by their unique id given when they join a server.


An RPC’s arguments are the following: mode, sync, transfer_mode, and transfer_channel

mode controls what clients can call the function as an RPC.

  • If it’s authority, then only the multiplayer authority (usually the server or host) can call this function on other clients.
  • if it’s any_peer, then any client can call this function on other clients.

sync controls what instances the RPC are called on. (This is confusing AF at first)

  • If it’s call_remote, the function will ONLY trigger for the client you called the RPC to.
  • If it’s call_local, the function will trigger for BOTH the client that called it and the client you called the RPC to.

I recommend only using call_remote, then do the local function for the sending client/server.

transfer_mode determines how the packet (information) is transmitted over the internet.

  • reliable means that the packet is guaranteed to reach the other client. However, it is slower than the other transfer modes. Use this for data that HAS to sync in order for your game to work.
  • unreliable means that the packet sends itself as fast as possible, but has a chance of being lost in transit or being out of order.
  • unreliable_ordered means that the packet sends itself as fast as possible, but will always be received in the correct order. This is great for syncing player movement.

transfer_channel is a little hard to explain. Imagine a channel being a road, each road can only send one RPC at a time. So having multiple roads will allow you to send multiple RPCs as once.

The channel is determined by a number starting from 0. As a brief example:

  • Channel 0 is the main gameplay functions.
  • Channel 1 is the non-gameplay functions like text chat.
  • Channel 2is for non-time-sensitive data transfer like stats.
  • Etc. You can be as creative as you want.

There’s a lot more to RPC, as every game has specific needs, but I hope this helps.

4 Likes

Private or Public they are still RPCs; if by “security” you mean obscurity then no, the private functions are just as de-compilable as the public ones, private as a keyword only affects how other parts of your code access such members and methods, it’s not actually more hidden to the curious hacker.

2 Likes

Adding onto this, you could encrypt your game to delay data miners. But this generally isn’t worth it.

There’s actually an entire topic about this if your interested:

1 Like

Thank you a lot for the very thought out reply, I really appreciate that you even took the time to explain the different arguments and security features! I’ll definitely have to read up a bit more on RPCs before actually doing much with it.

I guess my concern was that having it in a public function would indirectly give it access to other functions that it shouldn’t have access to, which in turn would’ve been a security vulnerability. That might not have made a lot of sense but I’d like to factor in as many possibilities as possible which is why I thought I’d be better of asking here. I guess being presented with more options as opposed to the quite simple “func something():” on gdscript kind of made me think a few steps ahead.

1 Like

Thinking too far ahead is SO COMMON in game development, it’s crazy. I’ve done it so many times.

There’s actually a funny xkcd comic about this:

Also, I’m glad I could help. It took me a year to learn netcode and my game (Monkanics) STILL doesn’t work.

3 Likes

That’s hilarious, comforting to know I’m not the only one who does though!

On a side note, do you also do networking in C# or do you prefer gdscript for that?

1 Like

keep in mind anyone with a computer can do anything. someone can connect to your server and send it random data, they could send it a perfect string to call any RPC you have marked, they don’t have to have your game, they don’t have to have any of your source code. It’s important for your server to trust clients but verify everything being sent, if your coin pickup function requires an RPC, double check that the player sending it is actually near the coin.

2 Likes

Use GDscript. It’s a lot easier to learn and use. Plus, most help you’ll receive will be in GDscript.

C# is helpful, but not nessesary.

That was a fantastic explanation @Demetrius_Dixon. I’ve used @rpcs, and I am still learning about them. You taught me some things.

I’m curious about this statement. Can you expand upon why you recommend this?

1 Like

For certain network architectures, like a dedicated server, you want the server and client to do slightly different things.

In order to do so, you’d have the server perform it’s version of the function locally, then send the RPC call to the client to they do their version.

If you used call_local, it’d do the same thing on both the client and server. If implemented wrong, you could end up performing the same function twice on the server.

Fair enough. For a dedicated server it makes more sense, because it likely won’t do the thing at all - like have a player.

True that, and I am careful with what I put in an RPC function. Regardless of how I declare the RPC function (private, public, etc), a malicious user shouldn’t be able to call a non-RPC function unless I deliberately call that function by myself in the code, right?

Due to save/load features I will need to be able to read/write to a save file, but I’m assuming as long as no RPC actually calls the functions that handle saving there should be no issue.

1 Like

Yeah true, I’m mostly just messing around trying to learn honestly.

1 Like

A malicious user cannot call a non-RPC function.

Your save file is safe on the server so long as you do not take user input at face value. For example if you save usernames in a CSV format be prepared for usernames with commas to mess things up, or even non-printable characters to come your way.

3 Likes