Saltar al contenido principal

Aislamiento de contexto

¿Qué es?

Context Isolation es una característica que asegura que tanto los scripts preload como la lógica interna de Electron se ejecuten en un contexto separado al sitio web que carga en un webContents. Esto es importante para propósitos de seguridad, ya que ayuda a evitar que el sitio web acceda a los internos de Electron o a las poderosas APIs a las que tu script de precarga tiene acceso.

This means that the window object that your preload script has access to is actually a different object than the website would have access to. Por ejemplo, si establece en su script de precarga window.hello = 'wave' y el aislamiento de contexto está habilitado, window.hello será undefined si el sitio web trata de acceder a él.

El aislamiento de contexto está habilitado por defecto desde Electron 12, y es una configuración de seguridad recomendada para todas las aplicaciones.

Migración

Sin aislamiento de contexto, solía proporcionar API desde mi script de precarga utilizando window.X = apiObject. ¿Y ahora qué?

Antes: aislamiento de contexto desactivado

Exponer APIs desde su script de precarga a un sitio web cargado en el proceso de renderizado es un caso de uso común. Con el aislamiento contextual deshabilitado, su script de precarga compartiría un objeto global window común con el renderizador. A continuación, puedes adjuntar propiedades arbitrarias a un script de precarga:

preload.js
// precargar con contextIsolation deshabilitado
window.myAPI = {
doAThing: () => {}
}

La función doAThing() podría luego ser usada directamente en el proceso renderizador:

renderer.js
// use la API expuesta en el renderer
window.myAPI.doAThing()

Después: aislamiento de contexto activado

Hay un módulo dedicado en Electron para ayudarle a hacer esto de una manera más sencilla. The contextBridge module can be used to safely expose APIs from your preload script's isolated context to the context the website is running in. La API también será accesible desde el sitio web en window.myAPI tal como estaba antes.

preload.js
// precarga con contextIsolation habilitado
const { contextBridge } = require('electron')

contextBridge.exposeInMainWorld('myAPI', {
doAThing: () => {}
})
renderer.js
// use la API expuesta en el renderer
window.myAPI.doAThing()

Por favor lea la documentación de contextBridge enlazada arriba para entender completamente sus limitaciones. Por ejemplo, no puede enviar prototipos personalizados o símbolos sobre el puente.

Consideraciones de Seguridad

Sólo activar contextIsolation y usar contextBridge no significa automáticamente que todo lo que hagas esté seguro. Por ejemplo, este código es inseguro.

preload.js
// ❌ Bad code
contextBridge.exposeInMainWorld('myAPI', {
send: ipcRenderer.send
})

Expone directamente una poderosa API sin ningún tipo de filtrado de argumentos. Esto permitiría a cualquier sitio web enviar mensajes IPC arbitrarios, lo cual no deseas que sea posible. La forma correcta de exponer las APIs basadas en IPC sería proporcionar un método por mensaje IPPC.

preload.js
// ✅ Good code
contextBridge.exposeInMainWorld('myAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})

Uso con TypeScript

SI está construyendo su aplicación Electron con TypeScript, querrá añadir tipos a sus APIs expuestas sobre el puente del contexto. El objeto window del renderizador no tendrá los tipos correctos a menos que extienda los tipos con un declaration file.

Por ejemplo, dado este script preload.ts:

preload.ts
contextBridge.exposeInMainWorld('electronAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})

Puede crear un archivo de declaración interface.d.ts y aumentar globalmente la interfaz Window:

interface.d.ts
export interface IElectronAPI {
loadPreferences: () => Promise<void>,
}

declare global {
interface Window {
electronAPI: IElectronAPI
}
}

Al hacerlo se asegurará que el compilador de TypeScript sepa sobre la propiedad electronAPI en su objeto global window al escribir scripts en su proceso renderizador:

renderer.ts
window.electronAPI.loadPreferences()