Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Would it be safe to enable nodeIntegration in Electron on a local page that is packaged with the app?

I am stuck when creating custom window controls like close, min/max and restore with nodeIntegration turned off. I created the buttons in my renderer's local html file

main.js

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')
}));

index.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>

By default, nodeIntegration is off so index.js has no access to Node. However, I need to be able to add functionality to the buttons to close, min/max and restore the window.

index.js

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

document.getElementById('close').addEventListener('click', () => {
  mainWindow.close();
});

This wouldn't work because of nodeIntegration being disabled. Is it safe to have it enabled in a local page? If not, what is a safe way of doing this?

like image 336
AfterShotzZHD Avatar asked Aug 15 '19 05:08

AfterShotzZHD


People also ask

How do you enable nodeIntegration of an Electron?

Enable nodeIntegration option when creating a windowconst window = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, }, }); You should understand all potential security risk when enabling this option. Do not enable this option if you load some third-party resources to BrowserWindow.

What is Electron nodeIntegration?

Electron node integration refers to the ability of accessing Node. js resources from within the “renderer” thread (the UI). It is enabled by default in Quasar CLI, although Electron is encouraging developers to turn it off as a security precaution.

Is Electron a security risk?

However, Electron applications are notoriously known to have security issues. Since they combine traditional web technologies with the code running on and having access to the operating system through the Node.

Do you need node to run an Electron app?

To begin developing an Electron app, you need to install the Node. js runtime and its bundled npm package manager onto your system. We recommend that you use the latest long-term support (LTS) version. Please install Node.


2 Answers

TL;DR: Enabling nodeIntegration only imposes risks if you load and execute code from untrusted sources, i.e. the internet or from user input.

If you are completely sure that your application will only run the code you have created (and no NodeJS module loads scripts from the internet), basically, there is no to very little risk if enabling nodeIntegration.

However, if you allow the user to run code (i.e. input and then eval it) or you provide plug-in APIs from which you do not have any control over the plug-ins loaded, the risk level rises because NodeJS allows any NodeJS script, ex., to manipulate the filesystem.

On the other hand, if you disable nodeIntegration, you have no way of communicating with the main process or manipulating the BrowserWindow, thus cannot create custom window controls.

like image 115
Alexander Leithner Avatar answered Oct 28 '22 18:10

Alexander Leithner


Keep in mind, that in year 2021 you do not need nodeIntegration to communicate with the main process from the renderer process.

Instead, you use message passing, like this:
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.
}

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"));
});

This example illustrates two instances of message passing:

  1. When User clicks the #hideBtn button - a message is dispatched that instructs main to hide the window.
  2. By default the window is half-transparent; when User clicks on the window (essentially, activating the clickz event on the body) - a message is dispatched that instructs main to make the window fully opaque.
like image 34
avalanche1 Avatar answered Oct 28 '22 20:10

avalanche1