Безопасность по умолчанию
Программа на Electron работает с правами пользователя: может читать и удалять его файлы. Если в окно попадёт чужой скрипт — из заметки, скопированной из интернета, или со страницы, открытой по ссылке, — он получит те же права. Настройки безопасности ограничивают страницу так, чтобы такой скрипт ничего не мог сделать.
Три настройки окна
Все три включены по умолчанию в актуальных версиях Electron. Явно их можно записать так:
// main.js
const win = new BrowserWindow({
width: 900,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
},
});Писать их не обязательно, поведение будет таким же. Явная запись полезна как напоминание тем, кто будет читать код.
| Настройка | Значение по умолчанию | Что делает |
|---|---|---|
nodeIntegration | false | Страница не может вызвать require и использовать Node.js |
contextIsolation | true | Скрипт preload и страница работают в разных мирах JavaScript |
sandbox | true | Процесс отрисовки ограничен системой, как вкладка Chrome |
Изоляция контекста
С изоляцией у preload и у страницы разные объекты window. Страница не может подменить функцию, которую использует preload, и не может добраться до ipcRenderer. Она видит только то, что положено через contextBridge.exposeInMainWorld.
Content-Security-Policy
CSP — правило, откуда странице можно загружать скрипты, стили и картинки. Оно задаётся тегом meta в index.html:
<!-- index.html -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src 'self' data:">'self' разрешает файлы только из папки программы, img-src дополнительно разрешает картинки в формате data:. Встроенные скрипты и чужие сайты запрещены: даже если в заметку попадёт тег script, он не выполнится.
Узкий мост
Через contextBridge передавайте отдельные функции с понятным назначением:
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('notes', {
save: (list) => ipcRenderer.invoke('notes:save', list),
});Страница может только сохранить заметки. Если бы preload отдал весь ipcRenderer, страница могла бы отправить любое сообщение главному процессу.
Другие правила
- Выводите пользовательский текст через
textContent, а неinnerHTML. - Не открывайте чужие сайты в окне со своим preload. Внешние ссылки открывайте в браузере через
shell.openExternal(url)в главном процессе. - Обновляйте Electron: в новых версиях исправлены уязвимости Chromium.
Частая ошибка
Встретив ошибку require is not defined, новички ставят nodeIntegration: true и contextIsolation: false — так советуют старые статьи. После этого любой скрипт на странице получает полный доступ к компьютеру. Оставьте настройки по умолчанию и перенесите работу с Node.js в главный процесс, а странице дайте функцию через preload.