I think as soon as you add mods to your application that can bring their own code with them you have a potential security issue. The most secure approach that I have seen is wasm mods/plugins run in a sandbox.
Programming
Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!
Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.
Hope you enjoy the instance!
Rules
Rules
- Follow the programming.dev instance rules
- Keep content related to programming in some way
- If you're posting long videos try to add in some form of tldr for those who don't want to watch videos
Wormhole
Follow the wormhole through a path of communities [email protected]
Turing completeness and making functions, which can be used in combination of choice, available to the modder is a security nightmare I guess (basically your game becomes a simple operating system by making it programmable). I heard web-assembly allows for "sandboxing" but that depends on the hook functions that you allow your modder to access as well ….
But web-browsers seem to do it fine with their APIs.
For your holy-mod-sword
example specifically, the better approach is to specify a structured data format (think Excel sheets) that your game loads from a specific directory at startup and inserts the found items, NPCs etc. into the game's runtime data structures (e.g. loot tables).
For example, Skyrim (and other Bethesda games) do this with .esp-files, which allow you to import a big variety of different game entities. In a small indie game, the format doesn't have to be anything special; e.g. Elin modders use plain .xlsx files, where the columns are item name, item weight, item sell value, item damage, etc.
The above approach works for static data, such as simple items, but you'll need more to allow modders to write Turing complete scripts. There are two different approaches to this:
- Expose a language runtime in which the game runs mods. You can design your own language and/or runtime (e.g. Warcraft 3 has JASS), or use existing ones (this is basically what
eval
is, though you'll need to hide builtins, globals and such by passing extra parameters). These approaches are theoretically safe thanks to the runtime sandbox, but there are often unintended ways to escape the sandbox and execute arbitrary code. - Inject the mod executable directly into the game with tools like BepInEx (Unity) or DLL injection (used by e.g. Skyrim Script Extender). There are no security guard rails, so you'll need to manually review mods.
TIL about BepInEx thanks! I will have to learn more about DLL injection.
no security guard rails, so you’ll need to manually review mods
I think we all know how this ends in practice … Gamers review all their mods code before playing
Usually, when games and programs natively support 3rd party mods/plugins its done so through a defined API - a modding API - just a bunch of functions made by the devs that allow you to register new stuff, change/override what already exists, react to events, ... Example https://lua-api.factorio.com/latest/
Lua is often used as the language for the mods because it's really easy to embed into a program (most games are done in compiled languages) and so creates a "sandbox" - you can only really call what the devs make available for the lua scripts.
Eval is bad for security boundaries and the string based approach is a pain to develop and maintain. An alternative that is equally bad for security but better for development would be dynamic imports using importlib.
If you want to support custom scripts while enforcing security boundaries, you could use an embeddable interpreter like lua, or create your own.