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

构建类LeetCode网站:无需容器化的Python用户代码沙箱方案咨询

无容器化的代码沙箱防护方案(针对类LeetCode平台)

针对不使用容器化技术的场景,可从语言层拦截、系统层隔离、执行环境管控、静态前置检查四个维度构建沙箱,以下是具体实现思路和技术方案:

一、语言层面的危险操作拦截

针对Python、JavaScript这类动态语言,直接在语言 runtime 层面限制危险行为:

1. 模块/函数黑白名单机制

  • 自定义导入拦截器:通过语言的导入钩子,拦截危险模块的加载。以Python为例,实现MetaPathFinder来过滤黑名单模块:
    import sys
    from importlib.abc import MetaPathFinder
    
    class RestrictedImporter(MetaPathFinder):
        # 禁止导入的危险模块
        BLACKLIST = {"os", "subprocess", "shutil", "socket"}
    
        def find_spec(self, fullname, path, target=None):
            if fullname in self.BLACKLIST:
                raise ImportError(f"禁止导入模块: {fullname}")
            return None
    
    # 注入拦截器到导入链最前端
    sys.meta_path.insert(0, RestrictedImporter())
    
  • 危险函数重写:对已导入模块的危险方法进行替换,使其失效或抛出异常:
    import os
    # 替换os.remove为无操作/抛出权限错误
    os.remove = lambda *args: _raise_permission_error()
    os.unlink = lambda *args: _raise_permission_error()
    
    def _raise_permission_error():
        raise PermissionError("该操作已被系统禁止")
    
    注意:需覆盖所有危险函数的别名(如from os import remove的场景,需结合静态分析提前拦截)。

2. 静态代码分析前置拦截

在执行代码前,通过抽象语法树(AST)扫描危险代码模式:

  • Python示例:遍历AST节点,检测危险函数调用和导入:
    import ast
    
    def check_dangerous_code(code):
        tree = ast.parse(code)
        dangerous_calls = {"os.remove", "os.unlink", "subprocess.run", "exec", "eval"}
        dangerous_imports = {"os", "subprocess"}
    
        for node in ast.walk(tree):
            # 检查导入语句
            if isinstance(node, ast.Import):
                for alias in node.names:
                    if alias.name in dangerous_imports:
                        return False, f"禁止导入危险模块: {alias.name}"
            elif isinstance(node, ast.ImportFrom):
                if node.module in dangerous_imports:
                    return False, f"禁止导入危险模块: {node.module}"
            # 检查函数调用
            elif isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute):
                call_path = f"{node.func.value.id}.{node.func.attr}"
                if call_path in dangerous_calls:
                    return False, f"禁止调用危险函数: {call_path}"
        return True, "代码检测通过"
    

二、操作系统层面的资源隔离

利用操作系统原生机制限制进程权限和资源:

1. 系统调用过滤(Linux)

使用Seccomp限制进程可调用的系统调用,仅允许必要的操作(如read、write、exit):

import seccomp

def setup_seccomp_rules():
    # 初始化过滤器,默认允许所有调用,再禁止危险调用
    filter = seccomp.SyscallFilter(seccomp.Activation.ACT_ALLOW)
    # 禁止文件删除、进程创建、执行等危险调用
    dangerous_syscalls = ["unlink", "unlinkat", "rmdir", "execve", "fork", "clone"]
    for syscall in dangerous_syscalls:
        filter.add_rule(seccomp.Action.ACT_KILL, syscall)
    # 加载过滤器
    filter.load()

执行用户代码前,先切换到nobody等低权限用户(os.setuid(65534)),再加载Seccomp规则。

2. 资源配额限制

通过ulimit/setrlimit限制进程的CPU、内存、文件资源:

import resource

def set_resource_limits():
    # CPU时间限制(1秒)
    resource.setrlimit(resource.RLIMIT_CPU, (1, 1))
    # 内存限制(256MB)
    resource.setrlimit(resource.RLIMIT_AS, (256 * 1024 * 1024, 256 * 1024 * 1024))
    # 最大文件大小(禁止创建大文件)
    resource.setrlimit(resource.RLIMIT_FSIZE, (1024 * 1024, 1024 * 1024))
    # 最大文件描述符数量
    resource.setrlimit(resource.RLIMIT_NOFILE, (32, 32))

三、执行环境的隔离管控

1. 独立子进程执行

用户代码必须在独立子进程中运行,主进程仅负责监控和通信:

  • Python示例:用multiprocessing创建隔离子进程,超时自动终止:
    import multiprocessing
    import time
    
    def run_user_code(code, result_queue):
        try:
            # 应用资源限制和Seccomp规则
            set_resource_limits()
            setup_seccomp_rules()
            # 执行用户代码
            exec(code)
            result_queue.put(("success", "执行完成"))
        except Exception as e:
            result_queue.put(("error", str(e)))
    
    def execute_sandboxed(code, timeout=5):
        result_queue = multiprocessing.Queue()
        process = multiprocessing.Process(target=run_user_code, args=(code, result_queue))
        process.start()
        # 等待进程结束或超时
        process.join(timeout)
        if process.is_alive():
            process.terminate()
            process.join()
            return ("timeout", "代码执行超时")
        return result_queue.get()
    

2. 文件系统隔离

  • 创建临时独立目录:用tempfile创建私有临时目录,切换到该目录后执行代码,设置目录权限为0o700(仅当前用户可访问)。
  • 使用内存文件系统(tmpfs):将临时目录挂载到tmpfs,避免用户代码写入磁盘,同时提升IO性能:
    mkdir /tmp/sandbox
    mount -t tmpfs -o size=100M tmpfs /tmp/sandbox
    

四、多语言适配注意事项

  • Java:可通过自定义ClassLoader限制类加载,或使用Java 9+的模块系统隔离权限;废弃的SecurityManager仍可在低版本Java中使用。
  • Go:通过syscall.ForkExec创建子进程,配合Seccomp过滤系统调用,同时设置RLIMIT_*资源限制。
  • C/C++:编译时添加-static静态编译,执行时应用Seccomp和资源限制,同时禁止进程访问敏感目录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 07:33:25