Skip to content

JavaScript: Add query for Node.js integration in Electron framework #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Sep 15, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions javascript/ql/src/Electron/EnablingNodeIntegration.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>

<overview>
<p>
Enabling Node.js integration in web content renderers (BrowserWindow, BrowserView and webview) could result in
remote native code execution attacks when rendering malicious JavaScript code from untrusted remote web site or
code that is injected via a cross site scripting vulnerability into the web content under processing. Please note that
the nodeIntegration property is enabled by default in Electron and needs to be set to 'false' explicitly.
</p>
</overview>

<recommendation>
<p>
Node.js integration should be disabled when loading remote web sites. If not possible, always set nodeIntegration property
to 'false' before loading remote web sites and only enable it for whitelisted sites.
</p>
</recommendation>

<example>
<p>
The following example shows insecure use of BrowserWindow with regards to <code>nodeIntegration</code>
property:
</p>
<sample src="examples/DefaultNodeIntegration.js"/>

<p>
This is problematic, because default value of nodeIntegration is 'true'.
</p>

</example>

<example>
<p>
The following example shows insecure and secure uses of </code>webview</code> tag:
Copy link
Contributor

@felicitymay felicitymay Sep 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes. It looks as if the Qhelp preview is just complaining about the typo in this line now.

</code>webview</code>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, will correct it after the code passes Language-Tests/JavaScript test

</p>
<sample src="examples/WebViewNodeIntegration.html"/>

</example>

<example>
<p>
The following example shows insecure and secure uses of BrowserWindow and BrowserView when
loading untrusted web sites:
</p>
<sample src="examples/EnablingNodeIntegration.js"/>

</example>


<references>
<li>Electron Documentation: <a href="https://electronjs.org/docs/tutorial/security#2-disable-nodejs-integration-for-remote-content">Security, Native Capabilities, and Your Responsibility</a></li>
</references>
</qhelp>
28 changes: 28 additions & 0 deletions javascript/ql/src/Electron/EnablingNodeIntegration.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @name Enabling nodeIntegration and nodeIntegrationInWorker in webPreferences
* @description Enabling nodeIntegration and nodeIntegrationInWorker could expose your app to remote code execution.
* @kind problem
* @problem.severity warning
* @precision very-high
* @tags security
* frameworks/electron
* @id js/enabling-electron-renderer-node-integration
*/

import javascript

string checkWebOptions(DataFlow::PropWrite prop, Electron::WebPreferences pref) {
(prop = pref.getAPropertyWrite("nodeIntegration") and
prop.getRhs().mayHaveBooleanValue(true) and
result = "nodeIntegration property may have been enabled on this object that could result in RCE")
or
(prop = pref.getAPropertyWrite("nodeIntegrationInWorker") and
prop.getRhs().mayHaveBooleanValue(true) and
result = "nodeIntegrationInWorker property may have been enabled on this object that could result in RCE")
or
(not exists(pref.asExpr().(ObjectExpr).getPropertyByName("nodeIntegration")) and
result = "nodeIntegration is enabled by default in WebPreferences object that could result in RCE")
}

from DataFlow::PropWrite property, Electron::WebPreferences preferences
select preferences,checkWebOptions(property, preferences)
2 changes: 2 additions & 0 deletions javascript/ql/src/Electron/examples/DefaultNodeIntegration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const win = new BrowserWindow();
win.loadURL("https://untrusted-site.com");
26 changes: 26 additions & 0 deletions javascript/ql/src/Electron/examples/EnablingNodeIntegration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//BAD
win_1 = new BrowserWindow({width: 800, height: 600, webPreferences: {nodeIntegration: true}});
win_1.loadURL("https://untrusted-site.com");

//GOOD
win_2 = new BrowserWindow({width: 800, height: 600, webPreferences: {nodeIntegration: false}});
win_2.loadURL("https://untrusted-site.com");

//BAD
win_3 = new BrowserWindow({
webPreferences: {
nodeIntegrationInWorker: true
}
});

//BAD BrowserView
win_4 = new BrowserWindow({width: 800, height: 600, webPreferences: {nodeIntegration: false}})
view = new BrowserView({
webPreferences: {
nodeIntegration: true
}
});
win.setBrowserView(view);
view.setBounds({ x: 0, y: 0, width: 300, height: 300 });
view.webContents.loadURL('https://untrusted-site.com');

15 changes: 15 additions & 0 deletions javascript/ql/src/Electron/examples/WebViewNodeIntegration.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>WebView Examples</title>
</head>

<body>
<!-- BAD -->
<webview src="https://untrusted-site.com/" nodeintegration></webview>

<!-- GOOD -->
<webview src="https://untrusted-site.com/"></webview>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
| EnablingNodeIntegration.js:5:28:11:9 | {\\n ... } | nodeIntegration property may have been enabled on this object that could result in RCE |
| EnablingNodeIntegration.js:5:28:11:9 | {\\n ... } | nodeIntegrationInWorker property may have been enabled on this object that could result in RCE |
| EnablingNodeIntegration.js:15:22:20:9 | {\\n ... } | nodeIntegration is enabled by default in WebPreferences object that could result in RCE |
| EnablingNodeIntegration.js:23:13:27:9 | {\\n ... } | nodeIntegration is enabled by default in WebPreferences object that could result in RCE |
| EnablingNodeIntegration.js:49:71:49:93 | {nodeIn ... : true} | nodeIntegration property may have been enabled on this object that could result in RCE |
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const {BrowserWindow} = require('electron')

function test() {
var unsafe_1 = {
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: true,
plugins: true,
webSecurity: true,
sandbox: true
}
};

var options_1 = {
webPreferences: {
plugins: true,
nodeIntegrationInWorker: false,
webSecurity: true,
sandbox: true
}
};

var pref = {
plugins: true,
webSecurity: true,
sandbox: true
};

var options_2 = {
webPreferences: pref,
show: true,
frame: true,
minWidth: 300,
minHeight: 300
};

var safe_used = {
webPreferences: {
nodeIntegration: false,
plugins: true,
webSecurity: true,
sandbox: true
}
};

var w1 = new BrowserWindow(unsafe_1);
var w2 = new BrowserWindow(options_1);
var w3 = new BrowserWindow(safe_used);
var w4 = new BrowserWindow({width: 800, height: 600, webPreferences: {nodeIntegration: true}});
var w5 = new BrowserWindow(options_2);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../../../../src/Electron/EnablingNodeIntegration.ql