在与应用程序一起打包的本地页面上启用 Electron 中的 nodeIntegration 是否安全?

Aft*_*ZHD 8 javascript node.js electron

在关闭 nodeIntegration 的情况下创建自定义窗口控件(如关闭、最小/最大和恢复)时,我被卡住了。我在渲染器的本地 html 文件中创建了按钮

主文件

mainWindow = new BrowserWindow({
    x, y, width, height,
    frame: false,
    show: false,
    webPreferences: { devTools: true }
});

mainWindow.loadURL(url.format({
    protocol: 'file:',
    slashes: true,
    pathname: path.join(__dirname, 'assets', 'index.html')
}));
Run Code Online (Sandbox Code Playgroud)

索引.html

<div id='minimize' class='noSelect'>&#xE921;</div>
<div id='maximize' class='noSelect'>&#xE922;</div>
<div id='restore' class='noSelect'>&#xE923;</div>
<div id='close' class='noSelect'>&#xE8BB;</div>

<script type='text/javascript' src='../assets/js/index.js'></script>
Run Code Online (Sandbox Code Playgroud)

默认情况下,nodeIntegration 处于关闭状态,因此index.js无法访问 Node。但是,我需要能够向按钮添加功能以关闭、最小/最大和恢复窗口。

索引.js

const { remote } = require('electron');
const mainWindow = remote.getCurrentWindow();

document.getElementById('close').addEventListener('click', () => {
  mainWindow.close();
});
Run Code Online (Sandbox Code Playgroud)

由于 nodeIntegration 被禁用,这将不起作用。在本地页面中启用它是否安全?如果没有,这样做的安全方法是什么?

Ale*_*ner 16

TL;DR:nodeIntegration仅当您从不受信任的来源(即互联网或用户输入)加载和执行代码时,启用才会带来风险。

如果您完全确定您的应用程序只会运行您创建的代码(并且没有 NodeJS 模块从 Internet 加载脚本),基本上,如果启用nodeIntegration.

但是,如果您允许用户运行代码(即输入然后eval它),或者您提供了插件 API,而您无法从中控制加载的插件,则风险级别会上升,因为 NodeJS 允许任何 NodeJS 脚本,例如,操作文件系统。

另一方面,如果禁用nodeIntegration,则无法与主进程通信或操作BrowserWindow,因此无法创建自定义窗口控件。

  • 这是一个很好的答案。有关禁用“nodeIntegration”的 IPC 示例,请参阅 /sf/answers/4035939701/ (4认同)
  • “预加载”脚本角度怎么样?如果不启用nodeIntegration,这会起作用吗? (2认同)

ava*_*he1 9

请记住,在2021年,您不需要与流程nodeIntegration进行沟通。mainrenderer

相反,您可以使用消息传递,如下所示:
main.js

const {app, BrowserWindow, ipcMain} = require("electron");
const path = require("path");

app.whenReady().then(open_window);

function open_window() {
  // Explain: Create app window.
  const appWin = new BrowserWindow({
    width: 800,
    height: 600,
    opacity: 0.5,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },

  // Explain: Render the app.
  void minisWindow.loadFile("index.html");
  
  // Spec: User can hide App window by clicking the button.
  ipcMain.on("hide-me", () => appWin.minimize());
  
  // Spec-start: When User focuses App window - it becomes fully opaque.
  ipcMain.on("make-window-opaque", () => appWin.setOpacity(1));
  appWin.on("show", () => minisWindow.setOpacity(1));
  appWin.on("blur", () => minisWindow.setOpacity(0.5));
  // Spec-end.
}

Run Code Online (Sandbox Code Playgroud)

preload.js

const {ipcRenderer} = require("electron");

// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener("DOMContentLoaded", () => {
  // Spec: User can hide App window by clicking the button.
  document.querySelector("#hideBtn").addEventListener("click", 
    () => ipcRenderer.send("hide-me"));
  });

  // Spec: When User focuses App window - it becomes fully opaque.
  document.body.addEventListener("click", () => ipcRenderer.send("make-window-opaque"));
});

Run Code Online (Sandbox Code Playgroud)

此示例说明了消息传递的两个实例:

  1. 当用户单击该#hideBtn按钮时 - 将发送一条消息,指示main隐藏窗口。
  2. 默认情况下,窗口是半透明的;当用户单击窗口时(本质上是激活clickz上的事件body) - 会调度一条消息,指示main使窗口完全不透明。

  • 恕我直言,这不是一个好的做法。您现在将属于渲染器的责任(处理 onClick)埋藏在 preload.js 中。人们应该使用 contextBridge 将 api 公开到渲染器中。渲染器处理onClick,调用contextBridge提供的api,preload/main执行不安全的代码。 (3认同)