diff --git a/atom.gyp b/atom.gyp index bf8b33655d..1dbf2c41a5 100644 --- a/atom.gyp +++ b/atom.gyp @@ -92,6 +92,8 @@ 'atom/browser/atom_browser_main_parts_mac.mm', 'atom/browser/atom_javascript_dialog_manager.cc', 'atom/browser/atom_javascript_dialog_manager.h', + 'atom/browser/atom_resource_dispatcher_host_delegate.cc', + 'atom/browser/atom_resource_dispatcher_host_delegate.h', 'atom/browser/browser.cc', 'atom/browser/browser.h', 'atom/browser/browser_linux.cc', diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index b62bc37b4b..d43b46783c 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -6,11 +6,13 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" +#include "atom/browser/atom_resource_dispatcher_host_delegate.h" #include "atom/browser/native_window.h" #include "atom/browser/net/atom_url_request_context_getter.h" #include "atom/browser/window_list.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "ui/base/l10n/l10n_util.h" @@ -54,6 +56,12 @@ net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext( CreateRequestContext(protocol_handlers); } +void AtomBrowserClient::ResourceDispatcherHostCreated() { + resource_dispatcher_delegate_.reset(new AtomResourceDispatcherHostDelegate); + content::ResourceDispatcherHost::Get()->SetDelegate( + resource_dispatcher_delegate_.get()); +} + void AtomBrowserClient::OverrideWebkitPrefs( content::RenderViewHost* render_view_host, const GURL& url, diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index 8f74dcfae6..afbc895f09 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -11,6 +11,8 @@ namespace atom { +class AtomResourceDispatcherHostDelegate; + class AtomBrowserClient : public brightray::BrowserClient { public: AtomBrowserClient(); @@ -22,6 +24,7 @@ class AtomBrowserClient : public brightray::BrowserClient { content::BrowserContext* browser_context, content::ProtocolHandlerMap* protocol_handlers, content::ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; + virtual void ResourceDispatcherHostCreated() OVERRIDE; virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host, const GURL& url, WebPreferences* prefs) OVERRIDE; @@ -37,6 +40,8 @@ class AtomBrowserClient : public brightray::BrowserClient { virtual brightray::BrowserMainParts* OverrideCreateBrowserMainParts( const content::MainFunctionParams&) OVERRIDE; + scoped_ptr resource_dispatcher_delegate_; + // The render process which would be swapped out soon. content::RenderProcessHost* dying_render_process_; diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc new file mode 100644 index 0000000000..30ddca2ae9 --- /dev/null +++ b/atom/browser/atom_resource_dispatcher_host_delegate.cc @@ -0,0 +1,50 @@ +// Copyright (c) 2014 GitHub, Inc. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/atom_resource_dispatcher_host_delegate.h" + +#include + +#include "base/logging.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/resource_request_info.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_request.h" + +namespace atom { + +namespace { + +const char* kDisableXFrameOptions = "disable-x-frame-options"; + +} // namespace + +AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() { +} + +AtomResourceDispatcherHostDelegate::~AtomResourceDispatcherHostDelegate() { +} + +void AtomResourceDispatcherHostDelegate::OnResponseStarted( + net::URLRequest* request, + content::ResourceContext* resource_context, + content::ResourceResponse* response, + IPC::Sender* sender) { + // Check if frame's name contains "disable-x-frame-options" + int p, f; + if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &p, &f)) + return; + content::RenderFrameHost* frame = content::RenderFrameHost::FromID(p, f); + if (!frame) + return; + if (frame->GetFrameName().find(kDisableXFrameOptions) == std::string::npos) + return; + + // Remove the "X-Frame-Options" from response headers. + net::HttpResponseHeaders* response_headers = request->response_headers(); + if (response_headers && response_headers->HasHeader("x-frame-options")) + response_headers->RemoveHeader("x-frame-options"); +} + +} // namespace atom diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.h b/atom/browser/atom_resource_dispatcher_host_delegate.h new file mode 100644 index 0000000000..10e993bcf0 --- /dev/null +++ b/atom/browser/atom_resource_dispatcher_host_delegate.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014 GitHub, Inc. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ +#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ + +#include "base/compiler_specific.h" +#include "content/public/browser/resource_dispatcher_host_delegate.h" + +namespace atom { + +class AtomResourceDispatcherHostDelegate + : public content::ResourceDispatcherHostDelegate { + public: + AtomResourceDispatcherHostDelegate(); + virtual ~AtomResourceDispatcherHostDelegate(); + + // content::ResourceDispatcherHostDelegate: + virtual void OnResponseStarted(net::URLRequest* request, + content::ResourceContext* resource_context, + content::ResourceResponse* response, + IPC::Sender* sender) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(AtomResourceDispatcherHostDelegate); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index be6357eb9e..3b9e7f0d09 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -18,6 +18,9 @@ win.show(); You can also create a window without chrome by using [Frameless Window](frameless-window.md) API. +Security strategy of web pages showed by `BrowserWindow` is a bit different from +normal browsers, see [Web Security](web-security.md) for more. + ## Class: BrowserWindow `BrowserWindow` is an @@ -51,8 +54,9 @@ You can also create a window without chrome by using * `show` Boolean - Whether window should be shown when created * `frame` Boolean - Specify `false` to create a [Frameless Window](frameless-window.md) - * `node-integration` String - Can be `all`, `except-iframe`, - `manual-enable-iframe` or `disable`. + * `node-integration` String - Default value is `except-iframe`, can also be + `all`, `manual-enable-iframe` or `disable`, see + [Web Security](web-security.md) for more informations. * `accept-first-mouse` Boolean - Whether the web view accepts a single mouse-down event that simultaneously activates the window * `auto-hide-menu-bar` Boolean - Auto hide the menu bar unless the `Alt` @@ -77,35 +81,6 @@ Creates a new `BrowserWindow` with native properties set by the `options`. Usually you only need to set the `width` and `height`, other properties will have decent default values. -By default the `node-integration` option is `except-iframe`, which means node -integration is disabled in all iframes, . You can also set it to `all`, with -which node integration is available to the main page and all its iframes, or -`manual-enable-iframe`, which is like `except-iframe`, but would enable iframes -whose name is suffixed by `-enable-node-integration`. And setting to `disable` -would disable the node integration in both the main page and its iframes. - -An example of enable node integration in iframe with `node-integration` set to -`manual-enable-iframe`: - -```html - - - - - -``` - -And in atom-shell, the security limitation of iframe is stricter than normal -browser, by default iframe is sandboxed with all permissions except the -`allow-same-origin`, which means iframe could not access parent's js context. - -If you want to enable things like `parent.window.process.exit()` in iframe, -you should explicitly set `sandbox` to `none`: - -```html - -``` - ### Event: 'page-title-updated' * `event` Event diff --git a/docs/api/web-security.md b/docs/api/web-security.md new file mode 100644 index 0000000000..fa78342dd1 --- /dev/null +++ b/docs/api/web-security.md @@ -0,0 +1,62 @@ +# Web Security + +Because atom-shell has added node integration to normal web pages, there are +some security adjustments that made atom-shell both more safe and more +convenient. + +## Overriding `X-Frame-Options` header + +May websites (including Google and Youtube) use the +[X-Frame-Options](x-frame-options) header to disable access to their websites +in `iframe`s. In atom-shell you can add a `disable-x-frame-options` string in +the `iframe`'s name to disable this: + +```html + + + + +``` + +## Frames are sandboxed by default + +In normal browsers, `iframe`s are not sandboxed by default, which means a remote +page in `iframe` can easily access its parent's JavaScript context. + +In atom-shell because the parent frame may have the power to access native +resources, this could cause security problems. In order to fix it, `iframe`s +in atom-shell are sandboxed with all permissions except the `allow-same-origin` +by default. + +If you want to enable things like `parent.window.process.exit()` in `iframe`s, +you need to explicitly add `allow-same-origin` to the `sandbox` attribute, or +just set `sandbox` to `none`: + +```html + +``` + +## Node integration in frames + +The `node-integration` option of [BrowserWindow](browser-window.md) controls +whether node integration is enabled in web page and its `iframe`s. + +By default the `node-integration` option is `except-iframe`, which means node +integration is disabled in all `iframe`s. You can also set it to `all`, with +which node integration is available to the main page and all its `iframe`s, or +`manual-enable-iframe`, which is like `except-iframe`, but enables `iframe`s +whose name contains string `enable-node-integration`. And setting to `disable` +would disable the node integration in both the main page and its `iframe`s. + +An example of enable node integration in `iframe` with `node-integration` set to +`manual-enable-iframe`: + +```html + + + + + +``` + +[x-frame-options](https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options)