Security features including safe storage, context isolation, sandboxing, and secure communication patterns.
Secure credential storage using system keychain services.
/**
* Allows access to simple encryption and decryption of strings for storage on the local machine
*/
interface SafeStorage {
/** Returns whether encryption is available */
isEncryptionAvailable(): boolean;
/** Encrypts a string and returns an encrypted buffer */
encryptString(plainText: string): Buffer;
/** Decrypts an encrypted buffer and returns the original string */
decryptString(encrypted: Buffer): string;
/** Sets the item data in the secure storage */
setPassword(service: string, account: string, password: string): void;
/** Retrieves the password from secure storage */
getPassword(service: string, account: string): string;
/** Deletes the password from secure storage */
deletePassword(service: string, account: string): boolean;
/** Returns the item data from secure storage */
findPassword(service: string): string;
}
declare const safeStorage: SafeStorage;Usage Examples:
const { safeStorage } = require('electron');
// Check if encryption is available
if (safeStorage.isEncryptionAvailable()) {
console.log('Safe storage is available');
// Encrypt sensitive data
const sensitiveData = 'user-secret-token';
const encrypted = safeStorage.encryptString(sensitiveData);
// Store encrypted data (you would save this to a file or database)
fs.writeFileSync('encrypted-data.bin', encrypted);
// Later, decrypt the data
const encryptedData = fs.readFileSync('encrypted-data.bin');
const decrypted = safeStorage.decryptString(encryptedData);
console.log('Decrypted:', decrypted);
// Store password in system keychain
safeStorage.setPassword('myapp', 'user@example.com', 'secret-password');
// Retrieve password
const password = safeStorage.getPassword('myapp', 'user@example.com');
console.log('Retrieved password:', password);
} else {
console.log('Safe storage is not available');
}Security through process isolation and controlled API access.
/**
* WebFrame controls the renderer frame's execution context
*/
interface WebFrame extends EventEmitter {
/** Inserts CSS into the current web page and returns a unique key for the inserted CSS */
insertCSS(css: string, options?: InsertCSSOptions): Promise<string>;
/** Removes the inserted CSS from the current web page */
removeInsertedCSS(key: string): Promise<void>;
/** Evaluates code in page */
executeJavaScript(code: string, userGesture?: boolean): Promise<any>;
/** Work like executeJavaScript but evaluates scripts in an isolated context */
executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean): Promise<any>;
/** Set the security origin, content security policy and name of the isolated world */
setIsolatedWorldInfo(worldId: number, info: IsolatedWorldInfo): void;
/** Resources will be loaded from this scheme regardless of the current page's Content Security Policy */
registerURLSchemeAsSecure(scheme: string): void;
/** Resources will be loaded from this scheme regardless of the current page's Content Security Policy */
registerURLSchemeAsBypassingCSP(scheme: string): void;
/** Registers the scheme as secure scheme */
registerURLSchemeAsPrivileged(scheme: string, options?: RegisterURLSchemeAsPrivilegedOptions): void;
/** Changes the zoom factor to the specified factor */
setZoomFactor(factor: number): void;
/** Returns the current zoom factor */
getZoomFactor(): number;
/** Changes the zoom level to the specified level */
setZoomLevel(level: number): void;
/** Returns the current zoom level */
getZoomLevel(): number;
/** Sets a provider for spell checking in input fields and text areas */
setSpellCheckProvider(language: string, provider: SpellCheckProvider): void;
/** The top frame in the frame hierarchy to which frame belongs */
readonly top: WebFrame;
/** The frame which opened frame, null if there's no opener or opener has been closed */
readonly opener: WebFrame | null;
/** The parent frame of frame, the property would be null if frame is the top frame in the frame hierarchy */
readonly parent: WebFrame | null;
/** The first child frame of frame, the property would be null if frame has no children */
readonly firstChild: WebFrame | null;
/** The next sibling frame of frame, the property would be null if frame is the last frame in the frame hierarchy */
readonly nextSibling: WebFrame | null;
/** A unique identifier for the frame */
readonly frameId: number;
/** The name of the frame */
readonly name: string;
/** The operating system pid of the process which owns this frame */
readonly processId: number;
/** The unique identifier for the frame's internal routing */
readonly routingId: number;
/** Whether the frame is out of process */
readonly isOutOfProcess: boolean;
/** The current URL of the frame */
readonly url: string;
}
declare const webFrame: WebFrame;Usage Examples:
// In renderer process with context isolation
const { webFrame } = require('electron');
// Execute code in isolated world
async function executeInIsolatedWorld() {
const worldId = 1000;
// Set up isolated world
webFrame.setIsolatedWorldInfo(worldId, {
securityOrigin: 'chrome-extension://my-extension-id',
csp: "script-src 'self' 'unsafe-inline';",
name: 'My Extension World'
});
// Execute code in isolated world
const result = await webFrame.executeJavaScriptInIsolatedWorld(worldId, [
{
code: `
// This code runs in isolation
window.myExtensionAPI = {
version: '1.0.0',
getData: () => 'isolated data'
};
'Isolated world setup complete';
`
}
]);
console.log('Isolated execution result:', result);
}
// Secure CSS injection
async function injectSecureCSS() {
const css = `
.secure-highlight {
background-color: yellow;
border: 2px solid red;
}
`;
const key = await webFrame.insertCSS(css, {
cssOrigin: 'user'
});
// Store key to remove later
window.injectedCSSKey = key;
}
// Remove injected CSS
async function removeSecureCSS() {
if (window.injectedCSSKey) {
await webFrame.removeInsertedCSS(window.injectedCSSKey);
delete window.injectedCSSKey;
}
}Secure preload script example:
// preload.js - Secure API exposure
const { contextBridge, ipcRenderer } = require('electron');
// Validate and sanitize input
function sanitizeInput(input) {
if (typeof input !== 'string') {
throw new Error('Input must be a string');
}
return input.replace(/[<>]/g, '');
}
// Expose secure API
contextBridge.exposeInMainWorld('secureAPI', {
// Safe methods
platform: process.platform,
version: process.versions.electron,
// Controlled file operations
readFile: (path) => {
// Validate path
if (!path || typeof path !== 'string') {
throw new Error('Invalid file path');
}
// Only allow certain directories
const allowedDirs = ['/app/data/', '/app/config/'];
const isAllowed = allowedDirs.some(dir => path.startsWith(dir));
if (!isAllowed) {
throw new Error('Access denied');
}
return ipcRenderer.invoke('secure-read-file', path);
},
// Safe IPC communication
sendMessage: (channel, data) => {
// Whitelist allowed channels
const allowedChannels = ['user-action', 'settings-update', 'log-message'];
if (!allowedChannels.includes(channel)) {
throw new Error('Channel not allowed');
}
// Sanitize data
const sanitizedData = sanitizeInput(JSON.stringify(data));
return ipcRenderer.invoke('secure-message', channel, JSON.parse(sanitizedData));
},
// Remove all listeners on cleanup
cleanup: () => {
ipcRenderer.removeAllListeners();
}
});CSP implementation for web content security.
/**
* Control the security policy of web content
*/
interface ContentSecurityPolicy {
/** Sets the Content Security Policy header */
setHeader(policy: string): void;
/** Gets the current Content Security Policy */
getHeader(): string | null;
/** Reports CSP violations */
reportViolation(violation: CSPViolation): void;
}
/**
* WebSecurity manages security settings for web content
*/
interface WebSecurity {
/** Disables web security warnings */
disable(): void;
/** Enables web security */
enable(): void;
/** Returns whether web security is enabled */
isEnabled(): boolean;
}Usage Examples:
// Set up Content Security Policy
const { BrowserWindow } = require('electron');
function createSecureWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
sandbox: true,
webSecurity: true,
allowRunningInsecureContent: false,
experimentalFeatures: false,
preload: path.join(__dirname, 'secure-preload.js')
}
});
// Set security headers
win.webContents.session.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': [
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline'; " +
"style-src 'self' 'unsafe-inline'; " +
"img-src 'self' data: https:; " +
"connect-src 'self' https: wss:; " +
"font-src 'self' data:; " +
"object-src 'none'; " +
"base-uri 'self'; " +
"form-action 'self';"
],
'X-Content-Type-Options': ['nosniff'],
'X-Frame-Options': ['DENY'],
'X-XSS-Protection': ['1; mode=block'],
'Referrer-Policy': ['strict-origin-when-cross-origin']
}
});
});
return win;
}
// Handle CSP violations
function setupCSPViolationHandler(session) {
session.webRequest.onBeforeRequest((details, callback) => {
// Log potential security violations
if (details.url.includes('evil-script.js')) {
console.warn('Blocked potentially malicious script:', details.url);
callback({ cancel: true });
return;
}
callback({});
});
}Control renderer process permissions and capabilities.
/**
* Permission management for web content
*/
interface PermissionManager {
/** Request permission for a specific capability */
requestPermission(permission: string, origin: string): Promise<boolean>;
/** Check if permission is granted */
checkPermission(permission: string, origin: string): boolean;
/** Revoke permission */
revokePermission(permission: string, origin: string): void;
/** List all granted permissions */
getGrantedPermissions(origin: string): string[];
}Usage Examples:
// Main process permission handling
const { session } = require('electron');
// Set up permission handlers
session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) => {
const { requestingUrl, isMainFrame } = details;
// Define permission policies
const permissionPolicies = {
'notifications': {
allowedOrigins: ['https://myapp.com', 'https://api.myapp.com'],
requiresMainFrame: true
},
'camera': {
allowedOrigins: ['https://myapp.com'],
requiresUserGesture: true
},
'microphone': {
allowedOrigins: ['https://myapp.com'],
requiresUserGesture: true
},
'geolocation': {
allowedOrigins: [],
requiresUserGesture: true
}
};
const policy = permissionPolicies[permission];
if (!policy) {
console.log(`Permission denied: ${permission} (no policy)`);
callback(false);
return;
}
// Check origin
const origin = new URL(requestingUrl).origin;
if (!policy.allowedOrigins.includes(origin)) {
console.log(`Permission denied: ${permission} (origin not allowed)`);
callback(false);
return;
}
// Check if main frame is required
if (policy.requiresMainFrame && !isMainFrame) {
console.log(`Permission denied: ${permission} (not main frame)`);
callback(false);
return;
}
console.log(`Permission granted: ${permission} for ${origin}`);
callback(true);
});
// Set up permission check handler
session.defaultSession.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
// Always allow for our app's origin
if (requestingOrigin === 'https://myapp.com') {
return true;
}
// Block everything else
return false;
});interface WebSource {
code: string;
url?: string;
startLine?: number;
}
interface IsolatedWorldInfo {
securityOrigin?: string;
csp?: string;
name: string;
}
interface RegisterURLSchemeAsPrivilegedOptions {
secure?: boolean;
bypassCSP?: boolean;
allowServiceWorkers?: boolean;
supportsFetchAPI?: boolean;
corsEnabled?: boolean;
stream?: boolean;
}
interface SpellCheckProvider {
spellCheck: (words: string[], callback: (misspeltWords: string[]) => void) => void;
}
interface CSPViolation {
directive: string;
effectiveDirective: string;
originalPolicy: string;
sourceFile: string;
sample: string;
disposition: 'enforce' | 'report';
statusCode: number;
lineNumber: number;
columnNumber: number;
}