如何在Electron中安全限制Node fs模块的访问权限?
Electron 文件系统访问权限限制方案(针对IPC/预加载API劫持风险)
针对你提到的Electron中文件系统API被劫持、权限过度开放的问题,以下是几个可落地的解决方案:
1. 动态路径白名单 + 严格路径校验
放弃硬编码固定目录的方案,改用动态白名单+路径合法性校验的组合:
- 仅允许访问用户主动选择的目录(比如通过原生文件对话框选择的文件夹),将这些路径加入白名单,操作完成后移除临时授权
- 在main进程处理文件操作前,对传入的路径做严格校验:
- 用
path.normalize()规范化路径,避免路径遍历攻击(如../) - 用
path.relative(allowedDir, targetPath)判断目标路径是否在允许的目录内,若返回值以../开头则直接拒绝 - 校验路径的真实存在性与文件类型,防止传入无效路径
- 用
示例代码(main进程):
const path = require('path'); const fs = require('fs/promises'); // 动态维护的允许目录白名单 const allowedDirs = new Set(); async function deleteFile(sender, targetPath) { // 规范化路径 const normalizedPath = path.normalize(targetPath); // 检查是否在允许的目录内 const isAllowed = Array.from(allowedDirs).some(dir => { const relative = path.relative(dir, normalizedPath); return !relative.startsWith('../') && relative !== '..'; }); if (!isAllowed) { throw new Error('无权访问该路径'); } // 执行删除操作 await fs.unlink(normalizedPath); }
2. 预加载API的最小权限封装
不要直接暴露fs的原始方法,而是封装成业务导向的受限API:
- 渲染进程只能调用业务相关的方法,比如
deleteImportedFile(fileId),而非直接传入路径 - 在main进程中维护文件ID与合法路径的映射关系,渲染进程无法接触到真实文件路径
- 开启
contextIsolation: true,通过contextBridge暴露API时,严格限制参数类型与范围,禁止传递任意字符串路径
示例代码(预加载脚本):
const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { // 仅暴露业务方法,不传递原始路径 deleteImportedFile: (fileId) => ipcRenderer.invoke('filesystem:delete-imported', fileId) });
3. IPC消息的会话级验证
针对预加载API可被劫持的问题,给每个窗口会话分配唯一标识,强化IPC验证:
- 窗口创建时生成唯一会话ID,通过预加载脚本传递给渲染进程
- 所有IPC消息必须携带该会话ID,main进程验证ID的合法性与对应权限
- 记录每个会话的操作范围(如允许访问的目录、操作类型),超出范围直接拒绝
4. 沙箱模式的精细化应用
对不需要Node.js权限的渲染进程开启sandbox: true:
- 沙箱模式下渲染进程无法直接访问Node.js API,只能通过预加载的受限API与main进程通信,大幅降低攻击面
- 对于需要部分权限的窗口,可通过
preload脚本暴露最小必要的API,避免权限过度开放
5. 临时权限授权机制
针对用户的合法跨目录操作需求,采用临时授权:
- 用户需要访问非默认目录时,通过Electron的
dialog.showOpenDialog()让用户主动选择目录 - main进程仅授权该目录的临时访问权限,操作完成后立即从白名单中移除
- 禁止通过渲染进程直接指定路径,所有路径必须由main进程通过原生对话框获取
内容的提问来源于stack exchange,提问作者Slbox
相关产品推荐
相关产品推荐

