跳到主要内容

webContents.executeJavaScript 有什么风险?什么时候可以用?

考察点​

  • 主进程能在页面里执行任意脚本
  • 字符串拼接用户输入就是 XSS

参考答案​

1. 能力​

await win.webContents.executeJavaScript('document.title');

这段字符串在页面的主世界里执行,能读 DOM、能调用 window.api。它不是隔离世界。

如果字符串里拼了用户名、文件名或服务端返回的内容:

// 危险:name 里可以包含引号和脚本
await win.webContents.executeJavaScript(
`window.renderReport("${name}")`
);

name 为 "); require('child_process')... 这类内容时,后果取决于页面当时有什么权限。即使 nodeIntegration 关着,它仍能调用你暴露的桥。

2. 可用的场景​

  • 自动化测试(Playwright 自己会用)
  • 打印窗口里注入已经在主进程序列化好的 JSON,并且用参数而不是拼接

相对安全的传法是让页面提供函数,主进程只把 JSON.parse 过的数据当参数:

const payload = JSON.stringify(report).replaceAll('<', '\\u003c');
await win.webContents.executeJavaScript(
`window.renderReport(${payload})`
);

JSON.stringify 避免了引号打断语法。再把 < 转掉,避免数据被当成 HTML。页面上的 renderReport 必须把参数当文本用,不能 innerHTML。

更好的做法是不用执行脚本:页面加载完成后 invoke 来取数据,或主进程 send 一份纯数据。

3. 不要用来“修”页面​

远程页面上注入脚本改 DOM、抓密码、自动点按钮,既脆弱也会把不可信页面和你的代码缠在一起。要改自己的页面就改源码。要隔离远程页面就用单独的 WebContentsView,不注入业务脚本。

executeJavaScriptInIsolatedWorld 跑在隔离世界,页面脚本看不到这段代码的变量,适合读 DOM。它仍然不应该拼接不可信字符串。

面试话术​

executeJavaScript 在页面主世界跑字符串,能碰到 window.api。用户输入和接口数据不能拼进这段字符串。页面要数据就用 send 或 invoke。真要注入,只注入 JSON.stringify 之后的参数,并让页面函数按文本渲染。远程页面不注入脚本。

常见追问​

  • 和 preload 比呢? preload 在每次加载时固定执行,代码在你的包里。executeJavaScript 是运行中临时塞一段,更难审计,所以不能当功能扩展机制。
  • 执行失败会怎样? 返回的 Promise reject。调用方要 catch,不要让一次打印失败变成未处理拒绝。