[Electron] 컨텍스트 격리(Context Isolation): 보안과 TypeScript로 더 안전하게

컨텍스트 격리(Context Isolation)란?

컨텍스트 격리는 Electron의 렌더러 프로세스에서 실행되는 JavaScript와 Preload 스크립트의 실행 환경을 분리하는 보안 메커니즘입니다. 즉, 웹 콘텐츠가 Electron 내부 API나 프리로드 스크립트에서 정의한 객체에 직접 접근하는 것을 차단합니다.

기본적으로 Electron 5.0.0부터 도입되었으며, Electron 12.0.0부터는 기본값으로 활성화되었습니다(contextIsolation: true) 

이 기능을 활성화하면 window 객체가 프리로드 스크립트와 웹 콘텐츠에서 서로 다른 인스턴스로 작동하게 됩니다. 예를 들어, 프리로드 스크립트에서 window.hello = 'wave'를 설정하더라도, 웹 콘텐츠에서는 window.helloundefined로 인식합니다.

  • 격리 전: 렌더러 프로세스는 Preload 스크립트와 동일한 JavaScript 컨텍스트를 공유하며, Node.js와 Electron API에 직접 접근 가능.
  • 격리 후: 렌더러와 Preload 스크립트가 별도의 컨텍스트에서 실행되며, 렌더러는 contextBridge로 노출된 API만 사용할 수 있음.

컨텍스트 격리 적용 방법

컨텍스트 격리 비활성화

// preload.js (contextIsolation 비활성화)
window.myAPI = {
  doSomething: () => console.log('Hello from preload!')
};
// renderer.js
window.myAPI.doSomething();

컨텍스트 격리 활성화

// preload.js
const { contextBridge } = require('electron');

contextBridge.exposeInMainWorld('myAPI', {
  doSomething: () => console.log('Hello from preload!')
});
// renderer.js
window.myAPI.doSomething();

TypeScript에서 컨텍스트 격리 적용하기

TypeScript로 개발할 경우, window 객체에 노출된 API가 올바르게 타입 체크되도록 설정해야 합니다.

// preload.ts
import { contextBridge, ipcRenderer } from 'electron';

contextBridge.exposeInMainWorld('electronAPI', {
  loadPreferences: () => ipcRenderer.invoke('load-prefs')
});
// interface.d.ts
export interface IElectronAPI {
  loadPreferences: () => Promise<void>;
}

declare global {
  interface Window {
    electronAPI: IElectronAPI;
  }
}
// renderer.ts
window.electronAPI.loadPreferences();