fix: security: don't allow arbitrary methods to be invoked on webContents via IPC (#15919)

This commit is contained in:
Milan Burda 2018-12-04 16:12:21 +01:00 committed by Alexey Kuzmin
parent 0a23c0b032
commit aa2b2f7c8f
7 changed files with 115 additions and 90 deletions

View file

@ -4,6 +4,7 @@ const { webContents } = require('electron')
const ipcMain = require('@electron/internal/browser/ipc-main-internal')
const parseFeaturesString = require('@electron/internal/common/parse-features-string')
const errorUtils = require('@electron/internal/common/error-utils')
const { syncMethods, asyncMethods } = require('@electron/internal/common/web-view-methods')
// Doesn't exist in early initialization.
let webViewManager = null
@ -368,7 +369,10 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL', function (event, request
new Promise(resolve => {
const guest = getGuest(guestInstanceId)
if (guest.hostWebContents !== event.sender) {
throw new Error('Access denied')
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
}
if (!asyncMethods.has(method)) {
throw new Error(`Invalid method: ${method}`)
}
if (hasCallback) {
guest[method](...args, resolve)
@ -388,9 +392,12 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_SYNC_CALL', function (event, guestIns
try {
const guest = getGuest(guestInstanceId)
if (guest.hostWebContents !== event.sender) {
throw new Error('Access denied')
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
}
event.returnValue = [null, guest[method].apply(guest, args)]
if (!syncMethods.has(method)) {
throw new Error(`Invalid method: ${method}`)
}
event.returnValue = [null, guest[method](...args)]
} catch (error) {
event.returnValue = [errorUtils.serialize(error)]
}

View file

@ -288,6 +288,11 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestI
if (guestWindow != null) guestWindow.destroy()
})
const windowMethods = new Set([
'focus',
'blur'
])
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) {
const guestContents = webContents.fromId(guestId)
if (guestContents == null) {
@ -295,7 +300,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guest
return
}
if (!canAccessWindow(event.sender, guestContents)) {
if (!canAccessWindow(event.sender, guestContents) || !windowMethods.has(method)) {
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
event.returnValue = null
return
@ -326,17 +331,27 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event,
}
})
const webContentsMethods = new Set([
'print',
'executeJavaScript'
])
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) {
const guestContents = webContents.fromId(guestId)
if (guestContents == null) return
if (canAccessWindow(event.sender, guestContents)) {
if (canAccessWindow(event.sender, guestContents) && webContentsMethods.has(method)) {
guestContents[method](...args)
} else {
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
}
})
const webContentsSyncMethods = new Set([
'getURL',
'loadURL'
])
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', function (event, guestId, method, ...args) {
const guestContents = webContents.fromId(guestId)
if (guestContents == null) {
@ -344,7 +359,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', function (e
return
}
if (canAccessWindow(event.sender, guestContents)) {
if (canAccessWindow(event.sender, guestContents) && webContentsSyncMethods.has(method)) {
event.returnValue = guestContents[method](...args)
} else {
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)

View file

@ -3,12 +3,20 @@
const ipcMain = require('@electron/internal/browser/ipc-main-internal')
// The history operation in renderer is redirected to browser.
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER', function (event, method, ...args) {
event.sender[method](...args)
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_GO_BACK', function (event) {
event.sender.goBack()
})
ipcMain.on('ELECTRON_SYNC_NAVIGATION_CONTROLLER', function (event, method, ...args) {
event.returnValue = event.sender[method](...args)
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD', function (event) {
event.sender.goForward()
})
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET', function (event, offset) {
event.sender.goToOffset(offset)
})
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER_LENGTH', function (event) {
event.returnValue = event.sender.length()
})
// JavaScript implementation of Chromium's NavigationController.