Hotdry.

Article

MicroPython + WASM 浏览器沙箱实战:从原理到可落地的安全执行环境

基于 Simon Willison 的 micropython-wasm 方案,详解如何在浏览器/服务器端构建 Python 沙箱,提供内存、CPU、文件系统的可控参数与最佳实践。

2026-06-07web

在 AI Agent 和插件系统蓬勃发展的今天,如何安全地执行不受信任的 Python 代码成为关键难题。传统方案要么依赖重量级容器,要么牺牲隔离性。Simon Willison 近期发布的 micropython-wasm alpha 包提供了一条轻量且实用的技术路径:将 MicroPython 编译为 WASI 标准的 WebAssembly 模块,通过 Wasmtime 在 Python 宿主中构建真正的沙箱执行环境。

为什么选择 MicroPython + WASM

WebAssembly 从设计之初就考虑了沙箱隔离性,经过浏览器环境近十年的实战检验。与直接将 CPython 嵌入宿主相比,WASM 方案具备天然优势:执行代码无法突破线性内存边界,无法直接访问宿主机文件系统或网络,且资源消耗可精确计量。

MicroPython 作为针对受限环境优化的 Python 实现,其精简特性恰好契合 WASM 的执行模型。相比 Pyodide(仅支持浏览器 / Node.js 环境),MicroPython 的 WASI 变体可以在服务器端 Python 环境中直接运行,填补了服务端轻量级沙箱的空白。

核心架构与资源控制

micropython-wasm 的技术架构包含三个关键层级:

WASM 运行时层:基于 Wasmtime Python 库,提供线性内存隔离和指令级 fuel 计数机制。每个执行实例拥有独立的 Store,确保状态完全隔离。

MicroPython 解释器层:通过 MicroPython PR #13676 的实验性 WASI 支持构建的 362KB WASM 二进制文件,内置精简标准库(支持 mathjsonrebinasciisys 等核心模块)。

宿主接口层:78 行 C 代码实现的 host 模块,提供 Python 函数回调机制,允许沙箱代码安全调用宿主定义的函数。

资源控制通过以下参数实现:

  • memory_bytes:限制 WASM 线性内存上限,默认 16MB。注意这仅限制客户机内存,宿主的运行时内存和回调开销不计入。
  • fuel:Wasmtime 的指令预算机制,默认 2000 万单位。当客户机执行超过此值时会被强制中断。实际使用中需根据代码复杂度调整,简单计算任务可能仅需数万 fuel,而复杂循环可能消耗数百万。
  • wall_timeout_seconds:墙钟超时,默认 1.0 秒。与 fuel 配合形成双重保险。
  • max_wasm_stack:WASM 调用栈上限,固定为 512KB。

两种会话模式的选择

根据状态持久化需求,micropython-wasm 提供两种 API 模式:

MicroPythonSession:在后台线程中保持 MicroPython VM 常驻内存,变量和导入的模块在多次 run() 调用间真正持久化。适合需要维护状态的交互式场景,如 REPL 或 Agent 工具链。

from micropython_wasm import MicroPythonSession

with MicroPythonSession(memory_bytes=16*1024*1024, fuel=20_000_000) as session:
    session.run("x = 10")
    result = session.run("print(x * 2)")  # 输出 20

MicroPythonReplaySession:无后台线程,每次 run() 创建全新 WASM 实例,通过重放历史代码片段重建状态。适合无状态、高并发的服务端场景,但需注意副作用(如文件写入、外部 API 调用)会被重复执行。

选择原则:需要真实状态持久化选 Session,追求隔离性和并发安全选 ReplaySession。

文件系统与网络隔离

默认配置下,沙箱代码无任何文件系统访问权限。如需提供输入数据,可通过 readonly_dir 参数将宿主目录以只读方式挂载到客户机的 /input 路径:

from micropython_wasm import run
from pathlib import Path

result = run(
    "print(open('/input/data.json').read())",
    readonly_dir=Path("./fixtures"),
)

网络访问在编译阶段即被禁用(socket 和 SSL 支持未启用)。如需受限网络能力,建议通过 host 函数暴露白名单控制的 HTTP 接口,而非开放原始 socket。

Host 函数:受控的能力透出

Host 函数机制是沙箱与宿主安全交互的桥梁。通过 register_function() 或构造参数将 Python 函数暴露给客户机,参数和返回值通过 JSON 序列化跨边界传输:

def fetch_data(endpoint: str, limit: int = 100):
    # 在宿主端执行受控的数据库查询
    return query_db(endpoint, limit)

session = MicroPythonSession(host_functions={"fetch": fetch_data})
result = session.run("print(fetch('users', limit=10))")

关键约束:只暴露幂等或无副作用的函数,避免暴露文件系统、环境变量、网络等敏感操作。

生产环境的安全加固

尽管 micropython-wasm 提供了合理的默认隔离,作者明确标注其为 alpha 版本,建议在高风险场景采取额外防护:

  1. 进程级隔离:每个执行单元运行在独立 worker 进程中,配合操作系统级的 cgroup 内存和 CPU 限制。
  2. 输出截断:限制 stdout/stderr 捕获大小,防止恶意代码通过大量输出消耗资源。
  3. 依赖锁定:固定 Wasmtime 和 MicroPython WASM 构件版本,定期回归测试。
  4. 权限最小化:Host 函数遵循最小权限原则,避免暴露环境变量、文件路径等敏感信息。

Simon Willison 的实测表明,即使 GPT-5.5 也无法突破当前沙箱边界,这为 AI Agent 场景提供了信心基础。

局限与应对

当前方案存在以下已知限制:

  • 标准库不完整hashlib.sha256zlib 等模块不可用,如需哈希计算需在宿主端实现。
  • Fuel 单位不直观:2000 万 fuel 对应多少实际计算难以预估,建议通过基准测试建立业务场景的 fuel 消耗模型。
  • 实验性依赖:MicroPython WASI 支持仍处于实验阶段,API 可能随上游更新而变化。

对于需要完整 CPython 兼容性的场景,可考虑 Pyodide + Web Worker 的浏览器方案,或 gVisor、Firecracker 等更重型的容器化方案作为补充。

总结

micropython-wasm 代表了服务端 Python 沙箱的务实演进方向:利用 WASM 的硬件级隔离能力,以极低的资源开销(362KB 二进制 + 可配置内存上限)实现真正的代码沙箱化。对于 AI Agent 插件系统、用户提交代码执行、动态配置脚本等场景,这套方案提供了可落地的技术路径。关键在于根据业务需求选择合适的会话模式,配置合理的资源限制,并通过 host 函数建立受控的安全边界。


参考来源

  • Simon Willison, "Running Python code in a sandbox with MicroPython and WASM", 2026-06-06
  • GitHub: simonw/micropython-wasm (alpha release)

web

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com