在本地运行一个陌生 Python 项目,风险不只是不小心 rm -rf。它可能读取 SSH key、扫描环境变量、改写你的源码目录,或者把私密文件发出去。这期播客讨论的核心问题很实际:能不能用 WASM 和 MicroPython 一类的运行时,把 Python 代码放进一个本地沙箱里执行,降低对宿主机的伤害面?
本地执行为什么危险
Python 的问题不在语言本身,而在默认权限太大。你在终端里运行:
python app.py
这段代码通常可以做这些事:
- 读取当前用户可读的文件,比如
~/.ssh/id_rsa、.env、浏览器缓存目录。 - 修改当前工作目录下的代码、测试数据、构建产物。
- 访问网络,把机器上的信息发出去。
- 调用系统命令,例如
subprocess.run(["curl", ...])。
虚拟环境只能隔离依赖,不能隔离权限。venv 防止包版本打架,却不会阻止恶意脚本读你的家目录。要处理“不可信代码”,需要进程、文件系统、网络和系统调用层面的边界。
WASM 沙箱的吸引力
WASM 的价值在于它默认不是一个完整操作系统。一个 WASM 模块能访问什么,通常需要宿主显式授予。文件系统、环境变量、网络、时钟、随机数等能力都可以被设计成“按需开放”。
这也是用 WASM 跑 Python 的思路:把解释器本身编译到 WASM,比如 MicroPython 的 WASM 形态,或者在浏览器里使用 Pyodide 这类 CPython/WASM 运行时。用户提供的 Python 代码进入 WASM 解释器,而不是直接进入宿主机的 Python 进程。
边界大致变成这样:
untrusted code.py
↓
Python interpreter compiled to WASM
↓
WASM runtime / browser sandbox
↓
explicitly granted files, APIs, and I/O
这不是魔法防弹衣。它减少的是默认权限,真正安全还要看宿主 API 暴露了什么、是否允许网络、是否挂载真实目录、是否限制 CPU 和内存。
可以这样实践:用浏览器里的 WASM Python 做本地试验
如果你的目标是 MicroPython,可以把下面例子里的运行时替换成 MicroPython 的 WASM 构建;这里用 Pyodide 演示同类模式,因为它可以直接复制成一个 HTML 文件运行,能清楚看到“代码在 WASM Python 里执行,而不是直接碰宿主文件系统”。
创建 sandbox.html:
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>Local Python WASM Sandbox</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 900px; margin: 32px auto; }
textarea { width: 100%; height: 220px; font-family: ui-monospace, monospace; }
pre { background: #111827; color: #e5e7eb; padding: 16px; overflow: auto; }
button { padding: 8px 14px; }
</style>
</head>
<body>
<h1>Local Python WASM Sandbox</h1>
<textarea id="code">print("hello from wasm python")
try:
open("/etc/passwd").read()
except Exception as exc:
print(type(exc).__name__, exc)</textarea>
<p><button id="run">Run</button></p>
<pre id="out"></pre>
<script src="https://cdn.jsdelivr.net/pyodide/v0.26.4/full/pyodide.js"></script>
<script>
const out = document.querySelector("#out");
const code = document.querySelector("#code");
const run = document.querySelector("#run");
let pyodideReady = loadPyodide({ stdout: append, stderr: append });
function append(text) {
out.textContent += text + "\n";
}
run.addEventListener("click", async () => {
out.textContent = "";
const pyodide = await pyodideReady;
try {
await pyodide.runPythonAsync(code.value);
} catch (err) {
append(String(err));
}
});
</script>
</body>
</html>
运行方式很朴素:
python3 -m http.server 8000
然后打开:
http://localhost:8000/sandbox.html
你可以改 textarea 里的代码做实验。它能运行 Python 逻辑,但不能像宿主机上的 python script.py 那样随便读取你的真实文件系统。这个例子适合用来验证产品交互、教学环境、代码片段演示,或者给用户提交的小段 Python 做低风险预览。
真要跑陌生代码,还要补几道闸
WASM 沙箱解决的是“默认能力太大”的问题,但生产环境不能只靠一句“用了 WASM”。可以按下面清单收紧:
- 不挂载宿主目录,或只挂载一次性临时目录。
- 默认关闭网络;确实需要网络时,通过代理白名单转发。
- 给运行设置超时,避免
while True: pass占满 CPU。 - 限制内存,避免用户代码制造大对象拖垮页面或进程。
- 捕获 stdout/stderr,不把宿主环境变量混进输出。
- 把包安装能力当成高风险能力处理,不允许任意安装和导入本地扩展。
对于浏览器内沙箱,还要注意:浏览器提供的是页面级环境,不是服务器安全边界。用户可以改前端代码,所以不要把密钥、评分逻辑、付费权限判断放进前端沙箱里。
采用建议
如果你只是检查一个开源项目是否可信,最稳妥的做法仍然是读代码、锁网络、使用临时账号或容器。WASM/MicroPython 更适合“运行小段 Python 代码”这种场景:在线教程、插件规则、表达式求值、面向用户的脚本框。
判断是否值得引入 WASM 沙箱,可以问三个问题:
- 代码是否来自不完全可信的用户或项目?
- 是否只需要 Python 语言子集,而不是完整 CPython 生态?
- 是否能接受文件、网络、系统调用能力被显式建模?
三个问题都接近“是”,WASM 沙箱就值得认真评估。它不会替你证明代码善良,但能把“本地随便跑”改成“给什么权限,才能碰什么东西”。