-
Notifications
You must be signed in to change notification settings - Fork 16.4k
Add sandbox option and support native window.open #6919
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
Conversation
af8043a
to
7187417
Compare
Hi again I'm done making changes and adding tests, so this is ready for review. This PR currently has some issues:
I want to fix all of these issues, but I prefer to do it in separate PRs as this one is very big already. Another possible issue(depending on the POV) is that browserify is now a build dependency and is used to provide commonjs for preload scripts in sandboxed renderers. I've opted to use browserify because is a very mature browser commonjs implementation and also was the fastest path to get a working commonjs environment in sandboxed renders. An alternative to using browserify would be to implement a commonjs environment that uses IPC to read files from disk using the main process, though I'd prefer to stick with browserify as it is cleaner than repeatedly loading a bunch of files via IPC. Finally think its worth mentioning that this PR adds a lot of code but the existing use cases of electron should not be affected by the changes made here. My goal is to allow electron to be used in more scenarios, such as implementing a web browser that shares some of chromium security features. |
|
||
content::WebContents* web_contents = GetWebContentsFromProcessID(process_id); | ||
if (WebContentsPreferences::IsSandboxed(web_contents)) { | ||
AddSandboxedRendererId(host->GetID()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be moved to BrowserClient::SiteInstanceGotProcess
? So we can get rid of the locker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only started playing with chromium content for this PR, so you tell me 😄
The locker is there because the sandboxed_renderers_
set is read from CanCreateWindow
(IO thread)/ShouldCreateNewSiteInstance
(UI thread) and written by RenderProcessWillLaunch
/RenderProcessHostDestroyed
which are both UI thread. BTW what is the simplest logic for determining which thread a method is called on, when no header comments are available? (other than printing the thread id to the console)
If you really want to get rid of the locker I suppose we could have a duplicate sandboxed_renderers_
set that is used by IO thread only(and updated with PostTask
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation, we can just use lock for now and see if we can do better optimization in future.
Add RenderFrameObserver/RenderViewObserver subclasses that implement the necessary support for preload scripts in sandboxed renderers.
The sandbox option allows multiple webContents in one renderer process, so using the only the renderer id to identify WebContents instances is no longer an option. WebContents::GetID now returns a 64-bit integer, which is composed of both the process id(high 32), and the RenderViewHost routing id(low 32). Also add a `GetProcessID` that retrieves the renderer process id, a requirement in some of our javascript code.
39a0600
to
47fd417
Compare
👍 |
@tarruda this seems interesting, are you going to add some docs to explain the option and what it gived to developers. There are some information in this thread, but it is not easy to find. |
Hi @tarruda, Understood ipcRenderer is exposed in the sandboxed renderer. Is there a plan to extend the list of exposed modules? for example websocket ? Thanks. |
I will add documentation later
It is possible that we'll eventually expose every module available to non-sandboxed renderers, but you can already achieve anything with |
@tarruda I agree for the security constraints and this the reason I'm interested in your contribution. However I also need to establish a communication with a standalone node.js process (non electron process). Websocket seems an easy option for a electron renderer to communicate with the node.js process. Is it possible to require the websocket module in the preload in js or this can only be achievable by modifying electron code ? Thanks |
I think the list of modules to expose should be passed with a new parameter such as sandboxAllowedModules. The default electron behavior will not be impacted and the change will give an opportunity for those who needs to support some more modules. Not sure if there is way to raise a change request here or if I need to create a PR. Thanks. |
I'm not an expert in the chrome sandbox architecture, but if I understood it correctly, the renderer is only allowed to communicate with the browser process, so even if we allow arbitrary node/electron modules to be required from the renderer, the entire API would be proxied using IPC(it would simply be hidden from you). Even network access is done via the browser process, so the renderer is never opening any network connections directly. If you simply want to use |
No need to create an issue a, simply use #6712 to track progress. I plan to implement it as soon as I get a free weekend, work/family have been demanding a lot lately :) |
That's fine, many thanks. |
@tarruda I would like your opinion about having a default preload used when we are in sandbox mode (and in that case no need to have preload attribute in webpreferences). |
Not sure if I understand what you mean by "default preload". Can you give an example? If you want to have a single preload API that exports all electron/node.js APIs to the renderer, then the sandbox won't help much(assuming you are using it for security purposes). |
Today with your solution all the developers who want to use sandbox have to manage on their side a preload for initiliazing some code (if they want to use it) for each application and depending if they want to activate or not the sandbox. |
There's no need to have a preload, you can simply use |
I think security whole in the master process can be exploited via IpcRenderer. If I need a pre-load file to expose ipcRenderer this is fine, I will just avoid to expose it. But if it is automatically exposed what is the best way to disable it before starting the renderer process ? |
Yes but for having window.open works correctly in sandbox mode I need to have some code to be loaded. That's why I ask the question (if some was interesting to have a fix for window.open). |
It is not automatically exposed. Since one of the main use cases of sandbox mode is enabling chromium sandbox for security, you have to explicitly create any extra APIs that use |
I already got that. I need that ipcRenderer not even be available in the Renderer process. |
In order to give more details: 'default preload' means for me specific code in init.js for renderer sandboxed |
// preload.js
window.ipcRenderer = require('electron').ipcRenderer
// ipcRenderer is a global variable visible to untrusted javascript. |
Great. This is what I wanted to confirm with you. |
This PR adds a
sandboxed
option that can be passed towebPreferences
ofBrowserWindow
constructor. Passing this option will completely change the renderer implementation of the new window: It won't have any node.js integration, and all system interaction happens through IPC.It also adds a
--enable-sandbox
command-line option that enables chromium OS-level sandbox for all renderers, and if this option is passed, then allBrowserWindow
instances will have thesandboxed
option passed automatically(since they would not work otherwise).This PR also restores chromium native
window.open
API for sandboxed windows as there should be no issue in having multiple webContents for one sandboxed renderer(since there's no node.js context)While the PR is relatively big, it is mostly made of required infrastructure changes to support the new code. The implementation is relatively simple: For renderers with the
sandboxed
option enabled, theAtomSandboxedRendererClient
class is used. This class is unrelated toAtomRendererClient
as it takes a very different approach to inject preload scripts and expose theipcRenderer
module(I've tried to reuse as much as possible, though). To support a basic commonjs environment in sandboxed renderers, browserify is used and integrated into the build system.I've tried to make commits small and self contained as possible, so reading each commit individually is the recommended way to review.
Close #1865