mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #167 from bnxi/NodeIntegration
Approved by esben-semmle
This commit is contained in:
49
javascript/ql/src/Electron/EnablingNodeIntegration.qhelp
Normal file
49
javascript/ql/src/Electron/EnablingNodeIntegration.qhelp
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Enabling Node.js integration in web content renderers (<code>BrowserWindow</code>, <code>BrowserView</code> and <code>webview</code>) 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 a trusted remote web site. Note that
|
||||
the <code>nodeIntegration</code> property is enabled by default in Electron and needs to be set to <code>false</code> 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 <code>BrowserWindow</code> with regards to <code>nodeIntegration</code>
|
||||
property:
|
||||
</p>
|
||||
<sample src="examples/DefaultNodeIntegration.js"/>
|
||||
|
||||
<p>
|
||||
This is problematic, because default value of <code>nodeIntegration</code> is 'true'.
|
||||
</p>
|
||||
|
||||
</example>
|
||||
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows insecure and secure uses of <code>BrowserWindow</code> and <code>BrowserView</code> 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>
|
||||
32
javascript/ql/src/Electron/EnablingNodeIntegration.ql
Normal file
32
javascript/ql/src/Electron/EnablingNodeIntegration.ql
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @name Enabling `nodeIntegration` or `nodeIntegrationInWorker` for Electron web content
|
||||
* @description Enabling `nodeIntegration` or `nodeIntegrationInWorker` can expose the application to remote code execution.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id js/enabling-electron-renderer-node-integration
|
||||
* @tags security
|
||||
* frameworks/electron
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* Gets a warning message for `pref` if one of the `nodeIntegration` features is enabled.
|
||||
*/
|
||||
string getNodeIntegrationWarning(Electron::WebPreferences pref) {
|
||||
exists (string feature |
|
||||
feature = "nodeIntegration" or
|
||||
feature = "nodeIntegrationInWorker" |
|
||||
pref.getAPropertyWrite(feature).getRhs().mayHaveBooleanValue(true) and
|
||||
result = "The `" + feature + "` feature has been enabled."
|
||||
)
|
||||
or
|
||||
exists (string feature |
|
||||
feature = "nodeIntegration" |
|
||||
not exists(pref.getAPropertyWrite(feature)) and
|
||||
result = "The `" + feature + "` feature is enabled by default."
|
||||
)
|
||||
}
|
||||
|
||||
from Electron::WebPreferences preferences
|
||||
select preferences, getNodeIntegrationWarning(preferences)
|
||||
@@ -0,0 +1,2 @@
|
||||
const win = new BrowserWindow();
|
||||
win.loadURL("https://untrusted-site.com");
|
||||
@@ -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');
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
| EnablingNodeIntegration.js:5:28:11:9 | {\\n ... } | The `nodeIntegrationInWorker` feature has been enabled. |
|
||||
| EnablingNodeIntegration.js:5:28:11:9 | {\\n ... } | The `nodeIntegration` feature has been enabled. |
|
||||
| EnablingNodeIntegration.js:15:22:20:9 | {\\n ... } | The `nodeIntegration` feature is enabled by default. |
|
||||
| EnablingNodeIntegration.js:23:16:27:9 | { // NO ... } | The `nodeIntegration` feature is enabled by default. |
|
||||
| EnablingNodeIntegration.js:49:74:49:96 | {nodeIn ... : true} | The `nodeIntegration` feature has been enabled. |
|
||||
@@ -0,0 +1,52 @@
|
||||
const {BrowserWindow} = require('electron')
|
||||
|
||||
function test() {
|
||||
var unsafe_1 = { // NOT OK, both enabled
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInWorker: true,
|
||||
plugins: true,
|
||||
webSecurity: true,
|
||||
sandbox: true
|
||||
}
|
||||
};
|
||||
|
||||
var options_1 = { // NOT OK, `nodeIntegrationInWorker` enabled
|
||||
webPreferences: {
|
||||
plugins: true,
|
||||
nodeIntegrationInWorker: false,
|
||||
webSecurity: true,
|
||||
sandbox: true
|
||||
}
|
||||
};
|
||||
|
||||
var pref = { // NOT OK, implicitly enabled
|
||||
plugins: true,
|
||||
webSecurity: true,
|
||||
sandbox: true
|
||||
};
|
||||
|
||||
var options_2 = { // NOT OK, implicitly enabled
|
||||
webPreferences: pref,
|
||||
show: true,
|
||||
frame: true,
|
||||
minWidth: 300,
|
||||
minHeight: 300
|
||||
};
|
||||
|
||||
var safe_used = { // NOT OK, explicitly disabled
|
||||
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}}); // NOT OK, `nodeIntegration` enabled
|
||||
var w5 = new BrowserWindow(options_2);
|
||||
var w6 = new BrowserWindow(safe_used);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Electron/EnablingNodeIntegration.ql
|
||||
Reference in New Issue
Block a user