You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何安全加载Python游戏模组并限制import、exec、eval等危险操作

游戏模组安全执行方案改进问题

问题背景

我开发了一款带模组框架(供模组开发者使用的API)的游戏,目录结构如下:

Game
├─ Info
│  └─ about.txt
├─ Packages
│  └─ mod1
│     ├─ main.txt
│     └─ data
│        └─ credits.txt
└─ run.py

模组的main.txt内容示例:

import requests # 不允许
userpassword = "peussweurdo"

open("Game/Info/About.txt", "r") # 允许
open("Game/Info/About.txt", "w") # 不允许

open("data/credits.txt") # 允许
open("C:/Users/<user>/passwords") # 不允许

核心需求

  • 确保模组无法使用import、exec和eval
  • 允许模组合法访问游戏相关资源

当前尝试的代码

import os

mod_path = "Packages/mod1/main.txt"
mod_data = open(mod_path, "r").read()

def safe_open(path, mode="r"):
    if path.startswith("Game") and mode != "r":
        raise OSError("Accessing game files is read-only")
    else:
        return open("%s/%s" % (mod_path, path), mode)

methods = {
    "open": safe_open
}
newly_defined = {}

exec(mod_data, methods, newly_defined)

存在的问题

当前方案会自动将所有内置函数加入methods字典,导致模组仍能调用import、exec和eval,不符合安全需求。


改进方案

要解决这个问题,需要手动构建干净的全局命名空间,只保留允许模组使用的内容,完全隔离内置的危险函数。具体实现如下:

1. 构建严格的全局执行环境

不依赖默认的内置函数集合,手动定义模组能访问的变量和函数,明确排除__import__、exec、eval等危险项:

import os
from pathlib import Path

# 获取模组所在根目录与游戏根目录
mod_file_path = "Packages/mod1/main.txt"
mod_root = Path(mod_file_path).parent.resolve()
game_root = Path(__file__).resolve().parent
mod_data = open(mod_file_path, "r").read()

def safe_open(path, mode="r"):
    target_path = Path(path).resolve()
    
    # 规则1:访问Game目录文件仅允许只读
    if game_root in target_path.parents or target_path == game_root:
        if mode != "r":
            raise OSError("Game目录文件仅支持只读访问")
        if not target_path.exists():
            raise FileNotFoundError(f"文件不存在:{path}")
        return open(target_path, mode)
    
    # 规则2:仅允许访问模组自身目录下的文件
    if mod_root in target_path.parents or target_path == mod_root:
        return open(target_path, mode)
    
    # 规则3:禁止访问其他外部路径
    raise OSError(f"禁止访问路径:{path}")

# 构建仅包含允许内容的全局命名空间
safe_globals = {
    # 按需添加允许的基础内置类型
    "str": str,
    "int": int,
    "float": float,
    "bool": bool,
    "list": list,
    "dict": dict,
    "tuple": tuple,
    # 替换为安全的open函数
    "open": safe_open,
    # 直接禁用import功能
    "__import__": lambda *args: raise ImportError("禁止导入任何模块")
}

# 使用严格环境执行模组代码
exec(mod_data, safe_globals, {})

2. 额外语法层面的安全校验

可以配合ast模块提前扫描模组代码,直接拦截包含import、exec、eval的代码:

import ast

def check_safe_code(code):
    tree = ast.parse(code)
    for node in ast.walk(tree):
        # 拦截import语句
        if isinstance(node, (ast.Import, ast.ImportFrom)):
            raise SyntaxError("禁止使用import语句")
        # 拦截exec/eval调用
        if isinstance(node, ast.Expr) and isinstance(node.value, ast.Call):
            if isinstance(node.value.func, ast.Name) and node.value.func.id in ["exec", "eval"]:
                raise SyntaxError("禁止使用exec/eval函数")
    return tree

# 先校验代码安全性,再执行
check_safe_code(mod_data)
exec(mod_data, safe_globals, {})

通过执行环境隔离+语法前置校验的双重机制,既能彻底阻止模组使用危险功能,也能保证合法的资源访问需求。

内容的提问来源于stack exchange,提问作者Dimsey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 23:16:01