Browse Source

Add option to override webview security

Hari Krishna Reddy Juturu 8 years ago
parent
commit
94d054cf11

+ 7 - 0
atom/browser/web_contents_preferences.cc

@@ -101,6 +101,13 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches(
   if (web_preferences.GetBoolean(options::kNodeIntegrationInWorker, &b) && b)
     command_line->AppendSwitch(switches::kNodeIntegrationInWorker);
 
+  // Check if webview tag creation is overriden.
+  bool enable_webview_override = false;
+  web_preferences.GetBoolean(options::kEnableWebViewOverride,
+                             &enable_webview_override);
+  command_line->AppendSwitchASCII(switches::kEnableWebViewOverride,
+                                  enable_webview_override ? "true" : "false");
+
   // If the `sandbox` option was passed to the BrowserWindow's webPreferences,
   // pass `--enable-sandbox` to the renderer so it won't have any node.js
   // integration.

+ 4 - 0
atom/common/options_switches.cc

@@ -128,6 +128,9 @@ const char kDisableBlinkFeatures[] = "disableBlinkFeatures";
 // Enable the node integration in WebWorker.
 const char kNodeIntegrationInWorker[] = "nodeIntegrationInWorker";
 
+// Enable the web view tag irrespective of node-integration setting.
+const char kEnableWebViewOverride[] = "enableWebViewOverride";
+
 }  // namespace options
 
 namespace switches {
@@ -172,6 +175,7 @@ const char kGuestInstanceID[]  = "guest-instance-id";
 const char kOpenerID[]         = "opener-id";
 const char kScrollBounce[]     = "scroll-bounce";
 const char kHiddenPage[]       = "hidden-page";
+const char kEnableWebViewOverride[]  = "enable-webview-override";
 
 // Command switch passed to renderer process to control nodeIntegration.
 const char kNodeIntegrationInWorker[]  = "node-integration-in-worker";

+ 2 - 0
atom/common/options_switches.h

@@ -64,6 +64,7 @@ extern const char kScrollBounce[];
 extern const char kBlinkFeatures[];
 extern const char kDisableBlinkFeatures[];
 extern const char kNodeIntegrationInWorker[];
+extern const char kEnableWebViewOverride[];
 
 }   // namespace options
 
@@ -93,6 +94,7 @@ extern const char kOpenerID[];
 extern const char kScrollBounce[];
 extern const char kHiddenPage[];
 extern const char kNodeIntegrationInWorker[];
+extern const char kEnableWebViewOverride[];
 
 extern const char kWidevineCdmPath[];
 extern const char kWidevineCdmVersion[];

+ 5 - 0
docs/api/browser-window.md

@@ -307,6 +307,11 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
       'Electron Isolated Context' entry in the combo box at the top of the
       Console tab. **Note:** This option is currently experimental and may
       change or be removed in future Electron releases.
+    * `enableWebViewOverride` Boolean (optional) - Whether to enable [webview-tag](webview-tag.md)
+      ignoring the security restriction based on `nodeIntegration`. Enabling this option will
+      have security implication on creating `webview` with `nodeIntegration` disabled. To avoid the
+      security risk, listen to `will-create-webview` event on [web-contents](web-contents.md) and 
+      stop creating `webview` or removing preload scripts.
 
 When setting minimum or maximum window size with `minWidth`/`maxWidth`/
 `minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from

+ 4 - 0
docs/api/webview-tag.md

@@ -15,6 +15,10 @@ between your app and embedded content will be asynchronous. This keeps your app
 safe from the embedded content. **Note:** Most methods called on the
 webview from the host page require a syncronous call to the main process.
 
+For security purposes, `webview` can only be used in `BrowserWindow`s that have
+`nodeIntegration` enabled. You can override this security restiction using
+`enableWebViewOverride` option on [browser-window](browser-window.md).
+
 ## Example
 
 To embed a web page in your app, add the `webview` tag to your app's embedder

+ 4 - 1
lib/renderer/init.js

@@ -57,6 +57,7 @@ let nodeIntegration = 'false'
 let preloadScript = null
 let isBackgroundPage = false
 let appPath = null
+let enableWebView = false
 for (let arg of process.argv) {
   if (arg.indexOf('--guest-instance-id=') === 0) {
     // This is a guest web view.
@@ -72,6 +73,8 @@ for (let arg of process.argv) {
     isBackgroundPage = true
   } else if (arg.indexOf('--app-path=') === 0) {
     appPath = arg.substr(arg.indexOf('=') + 1)
+  } else if (arg.indexOf('--enable-webview-override=') === 0) {
+    enableWebView = arg.substr(arg.indexOf('=') + 1)
   }
 }
 
@@ -94,7 +97,7 @@ if (window.location.protocol === 'chrome-devtools:') {
   require('./content-scripts-injector')
 
   // Load webview tag implementation.
-  if (process.guestInstanceId == null) {
+  if ((nodeIntegration === 'true' || enableWebView === 'true') && process.guestInstanceId == null) {
     require('./web-view/web-view')
     require('./web-view/web-view-attributes')
   }

+ 38 - 1
spec/webview-spec.js

@@ -8,7 +8,7 @@ const {closeWindow} = require('./window-helpers')
 
 const isCI = remote.getGlobal('isCi')
 
-describe('<webview> tag', function () {
+describe.only('<webview> tag', function () {
   this.timeout(3 * 60 * 1000)
 
   var fixtures = path.join(__dirname, 'fixtures')
@@ -36,6 +36,43 @@ describe('<webview> tag', function () {
     w.loadURL('file://' + fixtures + '/pages/webview-no-script.html')
   })
 
+  it('is disabled when nodeIntegration is disabled', function (done) {
+    w = new BrowserWindow({
+      show: false,
+      webPreferences: {
+        nodeIntegration: false,
+        preload: path.join(fixtures, 'module', 'preload-webview.js')
+      }
+    })
+    ipcMain.once('webview', function (event, type) {
+      if (type === 'undefined') {
+        done()
+      } else {
+        done('WebView still exists')
+      }
+    })
+    w.loadURL('file://' + fixtures + '/pages/webview-no-script.html')
+  })
+
+  it('is enabled when override is set', function (done) {
+    w = new BrowserWindow({
+      show: false,
+      webPreferences: {
+        nodeIntegration: false,
+        preload: path.join(fixtures, 'module', 'preload-webview.js'),
+        enableWebViewOverride: true
+      }
+    })
+    ipcMain.once('webview', function (event, type) {
+      if (type !== 'undefined') {
+        done()
+      } else {
+        done('WebView is not created')
+      }
+    })
+    w.loadURL('file://' + fixtures + '/pages/webview-no-script.html')
+  })
+
   describe('src attribute', function () {
     it('specifies the page to load', function (done) {
       webview.addEventListener('console-message', function (e) {