mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Do permission check when calling guest window methods
This commit is contained in:
committed by
Kevin Sawicki
parent
1f49da7a06
commit
1e36ee918e
@@ -9,9 +9,11 @@
|
||||
#include "atom/common/api/remote_callback_freer.h"
|
||||
#include "atom/common/api/remote_object_freer.h"
|
||||
#include "atom/common/native_mate_converters/content_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/hash.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "url/origin.h"
|
||||
#include "v8/include/v8-profiler.h"
|
||||
|
||||
namespace std {
|
||||
@@ -92,6 +94,10 @@ void TakeHeapSnapshot(v8::Isolate* isolate) {
|
||||
isolate->GetHeapProfiler()->TakeHeapSnapshot();
|
||||
}
|
||||
|
||||
bool IsSameOrigin(const GURL& l, const GURL& r) {
|
||||
return url::Origin(l).IsSameOriginWith(url::Origin(r));
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
@@ -105,6 +111,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
dict.SetMethod("createIDWeakMap", &atom::api::KeyWeakMap<int32_t>::Create);
|
||||
dict.SetMethod("createDoubleIDWeakMap",
|
||||
&atom::api::KeyWeakMap<std::pair<int32_t, int32_t>>::Create);
|
||||
dict.SetMethod("isSameOrigin", &IsSameOrigin);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const {BrowserWindow, ipcMain, webContents} = require('electron')
|
||||
const {isSameOrigin} = process.atomBinding('v8_util')
|
||||
|
||||
const hasProp = {}.hasOwnProperty
|
||||
const frameToGuest = {}
|
||||
@@ -100,6 +101,22 @@ const getGuestWindow = function (guestId) {
|
||||
return guestWindow
|
||||
}
|
||||
|
||||
// Checks whether |sender| can access the |target|:
|
||||
// 1. Check whether |sender| is the parent of |target|.
|
||||
// 2. Check whether |sender| has node integration, if so it is allowed to
|
||||
// do anything it wants.
|
||||
// 3. Check whether the origins match.
|
||||
//
|
||||
// However it allows a child window without node integration but with same
|
||||
// origin to do anything it wants, when its opener window has node integration.
|
||||
// The W3C does not have anything on this, but from my understanding of the
|
||||
// security model of |window.opener|, this should be fine.
|
||||
const canAccessWindow = function (sender, target) {
|
||||
return (target.getWebPreferences().openerId === sender.webContents.id) ||
|
||||
(sender.getWebPreferences().nodeIntegration === true) ||
|
||||
isSameOrigin(sender.getURL(), target.getURL())
|
||||
}
|
||||
|
||||
// Routed window.open messages.
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, frameName, disposition, options) {
|
||||
options = mergeBrowserWindowOptions(event.sender, options)
|
||||
@@ -113,18 +130,27 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', function (event, url, fr
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', function (event, guestId) {
|
||||
const guestWindow = getGuestWindow(guestId)
|
||||
if (guestWindow != null) guestWindow.destroy()
|
||||
if (guestWindow != null && canAccessWindow(event.sender, guestWindow.webContents)) {
|
||||
guestWindow.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guestId, method, ...args) {
|
||||
const guestWindow = getGuestWindow(guestId)
|
||||
event.returnValue = guestWindow != null ? guestWindow[method].apply(guestWindow, args) : null
|
||||
if (guestWindow != null && canAccessWindow(event.sender, guestWindow.webContents)) {
|
||||
event.returnValue = guestWindow[method].apply(guestWindow, args)
|
||||
} else {
|
||||
event.returnValue = null
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event, guestId, message, targetOrigin, sourceOrigin) {
|
||||
const guestContents = webContents.fromId(guestId)
|
||||
if (guestContents == null) return
|
||||
|
||||
// The W3C does not seem to have word on how postMessage should work when the
|
||||
// origins do not match, so we do not do |canAccessWindow| check here since
|
||||
// postMessage across origins is usefull and not harmful.
|
||||
if (guestContents.getURL().indexOf(targetOrigin) === 0 || targetOrigin === '*') {
|
||||
const sourceId = event.sender.id
|
||||
guestContents.send('ELECTRON_GUEST_WINDOW_POSTMESSAGE', sourceId, message, sourceOrigin)
|
||||
@@ -133,5 +159,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', function (event,
|
||||
|
||||
ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event, guestId, method, ...args) {
|
||||
const guestContents = webContents.fromId(guestId)
|
||||
if (guestContents != null) guestContents[method].apply(guestContents, args)
|
||||
if (guestContents != null && canAccessWindow(event.sender, guestContents)) {
|
||||
guestContents[method].apply(guestContents, args)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user