feat: add new fuse to treat file: identically to browsers (#40372)

This commit is contained in:
Samuel Attard 2023-11-09 10:23:52 -08:00 коммит произвёл GitHub
Родитель 0f68d845f9
Коммит d504d150ef
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 63 добавлений и 9 удалений

Просмотреть файл

@ -8,5 +8,6 @@
"node_cli_inspect": "1", "node_cli_inspect": "1",
"embedded_asar_integrity_validation": "0", "embedded_asar_integrity_validation": "0",
"only_load_app_from_asar": "0", "only_load_app_from_asar": "0",
"load_browser_process_specific_v8_snapshot": "0" "load_browser_process_specific_v8_snapshot": "0",
"grant_file_protocol_extra_privileges": "1"
} }

Просмотреть файл

@ -122,7 +122,7 @@ Example:
```js ```js
const { app, net, protocol } = require('electron') const { app, net, protocol } = require('electron')
const { join } = require('node:path') const path = require('node:path')
const { pathToFileURL } = require('url') const { pathToFileURL } = require('url')
protocol.registerSchemesAsPrivileged([ protocol.registerSchemesAsPrivileged([
@ -145,9 +145,19 @@ app.whenReady().then(() => {
headers: { 'content-type': 'text/html' } headers: { 'content-type': 'text/html' }
}) })
} }
// NB, this does not check for paths that escape the bundle, e.g. // NB, this checks for paths that escape the bundle, e.g.
// app://bundle/../../secret_file.txt // app://bundle/../../secret_file.txt
return net.fetch(pathToFileURL(join(__dirname, pathname)).toString()) const pathToServe = path.resolve(__dirname, pathname)
const relativePath = path.relative(__dirname, pathToServe)
const isSafe = relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath)
if (!isSafe) {
return new Response('bad', {
status: 400,
headers: { 'content-type': 'text/html' }
})
}
return net.fetch(pathToFileURL(pathToServe).toString())
} else if (host === 'api') { } else if (host === 'api') {
return net.fetch('https://api.my-server.com/' + pathname, { return net.fetch('https://api.my-server.com/' + pathname, {
method: req.method, method: req.method,

Просмотреть файл

@ -61,6 +61,19 @@ The onlyLoadAppFromAsar fuse changes the search system that Electron uses to loc
The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is used for the browser process. By default Electron's processes will all use the same V8 snapshot file. When this fuse is enabled the browser process uses the file called `browser_v8_context_snapshot.bin` for its V8 snapshot. The other processes will use the V8 snapshot file that they normally do. The loadBrowserProcessSpecificV8Snapshot fuse changes which V8 snapshot file is used for the browser process. By default Electron's processes will all use the same V8 snapshot file. When this fuse is enabled the browser process uses the file called `browser_v8_context_snapshot.bin` for its V8 snapshot. The other processes will use the V8 snapshot file that they normally do.
### `grantFileProtocolExtraPrivileges`
**Default:** Enabled
**@electron/fuses:** `FuseV1Options.GrantFileProtocolExtraPrivileges`
The grantFileProtocolExtraPrivileges fuse changes whether pages loaded from the `file://` protocol are given privileges beyond what they would receive in a traditional web browser. This behavior was core to Electron apps in original versions of Electron but is no longer required as apps should be [serving local files from custom protocols](./security.md#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) now instead. If you aren't serving pages from `file://` you should disable this fuse.
The extra privileges granted to the `file://` protocol by this fuse are incompletely documented below:
* `file://` protocol pages can use `fetch` to load other assets over `file://`
* `file://` protocol pages can use service workers
* `file://` protocol pages have universal access granted to child frames also running on `file://` protocols regardless of sandbox settings
## How do I flip the fuses? ## How do I flip the fuses?
### The easy way ### The easy way

Просмотреть файл

@ -759,6 +759,27 @@ function validateSender (frame) {
} }
``` ```
### 18. Avoid usage of the `file://` protocol and prefer usage of custom protocols
You should serve local pages from a custom protocol instead of the `file://` protocol.
#### Why?
The `file://` protocol gets more privileges in Electron than in a web browser and even in
browsers it is treated differently to http/https URLs. Using a custom protocol allows you
to be more aligned with classic web url behavior while retaining even more control about
what can be loaded and when.
Pages running on `file://` have unilateral access to every file on your machine meaning
that XSS issues can be used to load arbitrary files from the users machine. Using a custom
protocol prevents issues like this as you can limit the protocol to only serving a specific
set of files.
#### How?
Follow the [`protocol.handle`](../api/protocol.md#protocolhandlescheme-handler) examples to
learn how to serve files / content from a custom protocol.
[breaking-changes]: ../breaking-changes.md [breaking-changes]: ../breaking-changes.md
[browser-window]: ../api/browser-window.md [browser-window]: ../api/browser-window.md
[browser-view]: ../api/browser-view.md [browser-view]: ../api/browser-view.md

Просмотреть файл

@ -17,6 +17,7 @@
#include "content/public/common/content_constants.h" #include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "electron/buildflags/buildflags.h" #include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "extensions/common/constants.h" #include "extensions/common/constants.h"
#include "pdf/buildflags.h" #include "pdf/buildflags.h"
#include "ppapi/buildflags/buildflags.h" #include "ppapi/buildflags/buildflags.h"
@ -168,7 +169,9 @@ void ElectronContentClient::AddAdditionalSchemes(Schemes* schemes) {
&schemes->cors_enabled_schemes); &schemes->cors_enabled_schemes);
} }
schemes->service_worker_schemes.emplace_back(url::kFileScheme); if (electron::fuses::IsGrantFileProtocolExtraPrivilegesEnabled()) {
schemes->service_worker_schemes.emplace_back(url::kFileScheme);
}
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS) #if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
schemes->standard_schemes.push_back(extensions::kExtensionScheme); schemes->standard_schemes.push_back(extensions::kExtensionScheme);

Просмотреть файл

@ -56,6 +56,7 @@
#include "content/public/common/url_constants.h" #include "content/public/common/url_constants.h"
#include "crypto/crypto_buildflags.h" #include "crypto/crypto_buildflags.h"
#include "electron/buildflags/buildflags.h" #include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "electron/shell/common/api/api.mojom.h" #include "electron/shell/common/api/api.mojom.h"
#include "extensions/browser/extension_navigation_ui_data.h" #include "extensions/browser/extension_navigation_ui_data.h"
#include "mojo/public/cpp/bindings/binder_map.h" #include "mojo/public/cpp/bindings/binder_map.h"
@ -425,8 +426,10 @@ void ElectronBrowserClient::OverrideWebkitPrefs(
prefs->javascript_can_access_clipboard = true; prefs->javascript_can_access_clipboard = true;
prefs->local_storage_enabled = true; prefs->local_storage_enabled = true;
prefs->databases_enabled = true; prefs->databases_enabled = true;
prefs->allow_universal_access_from_file_urls = true; prefs->allow_universal_access_from_file_urls =
prefs->allow_file_access_from_file_urls = true; electron::fuses::IsGrantFileProtocolExtraPrivilegesEnabled();
prefs->allow_file_access_from_file_urls =
electron::fuses::IsGrantFileProtocolExtraPrivilegesEnabled();
prefs->webgl1_enabled = true; prefs->webgl1_enabled = true;
prefs->webgl2_enabled = true; prefs->webgl2_enabled = true;
prefs->allow_running_insecure_content = false; prefs->allow_running_insecure_content = false;

Просмотреть файл

@ -19,6 +19,7 @@
#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_thread.h"
#include "electron/buildflags/buildflags.h" #include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "printing/buildflags/buildflags.h" #include "printing/buildflags/buildflags.h"
#include "shell/browser/api/electron_api_protocol.h" #include "shell/browser/api/electron_api_protocol.h"
#include "shell/common/api/electron_api_native_image.h" #include "shell/common/api/electron_api_native_image.h"
@ -277,8 +278,10 @@ void RendererClientBase::RenderThreadStarted() {
// Allow file scheme to handle service worker by default. // Allow file scheme to handle service worker by default.
// FIXME(zcbenz): Can this be moved elsewhere? // FIXME(zcbenz): Can this be moved elsewhere?
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file"); if (electron::fuses::IsGrantFileProtocolExtraPrivilegesEnabled()) {
blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI("file"); blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file");
blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI("file");
}
#if BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_WIN)
// Set ApplicationUserModelID in renderer process. // Set ApplicationUserModelID in renderer process.