如何在PySide/PyQt绑定的Python沙箱中阻止文件读写?
解决方案:在Qt绑定环境下实现沙箱文件读写限制
可行方案汇总
方案1:Qt全局拦截与类重写
Qt的文件操作类(如QFile、QFileDialog)可通过重写或事件过滤拦截:
- 重写
QFile的open方法,直接返回失败并抛出权限错误; - 安装全局事件过滤器,拦截文件对话框的显示请求,直接拒绝;
- 代码示例(PySide6):
from PySide6.QtCore import QObject, QEvent, QFile, QIODevice from PySide6.QtWidgets import QApplication, QFileDialog class FileBlocker(QObject): def eventFilter(self, obj, event): if isinstance(obj, QFileDialog) and event.type() == QEvent.Show: obj.reject() return True return super().eventFilter(obj, event) # 安装全局过滤器 app = QApplication([]) blocker = FileBlocker() app.installEventFilter(blocker) # 重写QFile类 class RestrictedQFile(QFile): def open(self, mode): self.setErrorString("沙箱内禁止文件操作") return False # 替换全局QFile实现 import PySide6.QtCore PySide6.QtCore.QFile = RestrictedQFile
方案2:C++层面Hook Qt文件API
若Python重写存在绕过风险,可通过C++插件或动态注入拦截Qt底层文件操作:
- 编写Qt插件,替换
QFile::open等虚函数的实现; - 利用系统级动态链接注入(如Windows DLL注入、Linux LD_PRELOAD)拦截系统文件调用;
- C++示例片段(Hook
QFile::open):
#include <QFile> #include <QIODevice> typedef bool (*OriginalOpen)(QFile*, QIODevice::OpenMode); OriginalOpen originalOpen = nullptr; bool hookedOpen(QFile* file, QIODevice::OpenMode mode) { file->setErrorString("沙箱内禁止文件操作"); return false; } void initHook() { auto vtable = *reinterpret_cast<void***>(new QFile); // 需根据Qt版本调整虚函数索引 originalOpen = reinterpret_cast<OriginalOpen>(vtable[27]); vtable[27] = reinterpret_cast<void*>(hookedOpen); delete new QFile; }
方案3:增强RestrictedPython限制
结合现有RestrictedPython,扩展其规则覆盖Qt文件操作:
- 包装Qt文件类,拦截核心方法调用;
- 构建安全全局变量,替换危险API;
- 代码示例:
from RestrictedPython import compile_restricted, safe_globals def restricted_qfile_open(self, mode): raise PermissionError("沙箱内禁止文件操作") # 替换安全全局变量中的QFile safe_globals['QFile'] = type('RestrictedQFile', (safe_globals.get('QFile', object),), { 'open': restricted_qfile_open }) # 编译执行脚本 with open("script.py") as script: code = compile_restricted(script.read(), '<script>', 'exec') exec(code, safe_globals)
方案4:利用Qt系统沙箱机制(Qt 5.10+)
Qt提供的QSandbox类可对接系统级沙箱(如Windows AppContainer、Linux Flatpak):
- 配置文件系统访问权限为完全禁止;
- 注意:依赖系统平台支持,需适配不同系统策略;
- 代码示例:
from PySide6.QtCore import QSandbox sandbox = QSandbox() sandbox.setFileSystemAccess(QSandbox.NoAccess) sandbox.start()
关键注意事项
- 需覆盖所有Qt文件操作路径,包括
QTextStream、QDataStream等间接调用; - 动态Hook需适配不同Qt版本的函数偏移,可借助工具分析虚函数表;
- RestrictedPython包装要覆盖所有可能被脚本调用的Qt文件相关类,避免绕过。
内容的提问来源于stack exchange,提问作者Dante S.
相关产品推荐
相关产品推荐

