Given the complexity of the browser, our threat model must use a "defense in depth" approach to limit the damage that occurs if an attacker finds a way around the Same Origin Policy or other security logic in the renderer process. For example, the combination of Chrome's sandbox, IPC security checks, and Site Isolation limit what an untrustworthy renderer process can do. They protect Chrome users against attackers, even when such attackers are able to bypass security logic in the renderer process. For other arguments for the "defense in depth" approach and why our threat model covers compromised renderers, please see the Site Isolation motivation.
In a compromised renderer, an attacker is able to execute arbitrary native (i.e. non-JavaScript) code within the renderer process's sandbox. A compromised renderer can forge malicious IPC messages, impersonate a Chrome Extension content script, or use other techniques to trick more privileged parts of the browser.
The document below gives an overview of features that Chrome attempts to protect against attacks from a compromised renderer. Newly discovered holes in this protection would be considered security bugs and possibly eligible for the Chrome Vulnerability Rewards Program.
[TOC]
Most of the other protections listed in this document implicitly assume that attacker-controlled execution contexts (e.g. HTML documents or service workers) are hosted in a separate renderer process from other, victim contexts. This separation is called Site Isolation and allows the privileged browser process to restrict what origins a renderer process is authorized to read or control.
The privilege restriction can be implemented in various ways - see the
"protection techniques" listed in other sections in this document.
One example is validating in the browser process whether an incoming IPC can
legitimately claim authority over a given origin (e.g. by checking via
CanAccessDataForOrigin
if the process lock matches).
Another example is making sure that capabilities handed over to renderer
processes are origin-bound (e.g. by setting request_initiator_origin_lock
on a URLLoaderFactory
given to renderer processes).
Yet another example is making security decisions based on trustworthy knowledge,
calculated within the privileged browser process (e.g. using
RenderFrameHost::GetLastCommittedOrigin()
).
Compromised renderers shouldn’t be able to commit an execution context (e.g. commit a navigation to a HTML document, or create a service worker) in a renderer process hosting other, cross-site execution contexts. On desktop platforms all sites (site = scheme plus eTLD+1) should be isolated from each other. On Android, sites where the user entered a password should be isolated from each other and from other sites.
Known gaps in protection:
- No form of Site Isolation is active in Android WebView. See also https://crbug.com/769449.
- No form of Site Isolation is active in content hosted within
<webview>
HTML tags. See also https://crbug.com/614463. - Frames with
<iframe sandbox>
attribute are not isolated from their non-opaque precursor origin. See also https://crbug.com/510122. file:
frames may share a process with otherfile:
frames. See also https://crbug.com/780770.
Compromised renderers shouldn't be able to read the contents (header + body) of a cross-site HTTP response, unless it is a valid subresource needed for compatibility (e.g., JavaScript, images, etc), or is successfully allowed via CORS.
Protection techniques:
- Enforcing Cross-Origin Read Blocking (CORB) in the NetworkService process (i.e. before the HTTP response is handed out to the renderer process).
- Only allowing the privileged browser process to create
network::mojom::URLLoaderFactory
objects that handle HTTP requests. This lets the browser process carefully control security-sensitivenetwork::mojom::URLLoaderFactoryParams
of such factories (such asrequest_initiator_origin_lock
,is_corb_enabled
,disable_web_security
orisolation_info
). This also lets the CORB implementation in the NetworkService process prevent spoofing ofnetwork::ResourceRequest::request_initiator
by usingnetwork::GetTrustworthyInitiator
for comparison with the trustworthyrequest_initiator_origin_lock
.
Known gaps in protection:
- Content types for which CORB does not apply
(e.g.
image/png
,application/octet-stream
) are not protected by default. We recommend that HTTP servers protect such resources by either serving aCross-Origin-Resource-Policy: same-origin
response header or validating theSec-Fetch-Site
request header. - CORB protection is relaxed in presence of
- Adobe Flash plugin (see https://crbug.com/874515)
- A relatively small number of allowlisted Chrome Extensions (see https://crbug.com/846346)
Compromised renderers shouldn't be able to read the contents of cross-site frames. Examples:
- Text or pixels of cross-site frames.
- Full URL (e.g. URL path or query) of cross-site frames.
Note that the origin of other frames
needs to be exposed via
window.origin
for legacy reasons.
Protection techniques:
- Compositing tab contents (both for display and for printing) outside the renderer processes.
- Isolating PDF plugins.
- Being careful what URLs are exposed in console messages.
Known gaps in protection:
- Mixed content console messages may disclose cross-site URLs (see also https://crbug.com/726178).
Compromised renderers shouldn’t be able to read or write
any cookies of another site,
or httpOnly
cookies even from the same site.
Protection techniques:
- Renderer processes are only given
network::mojom::RestrictedCookieManager
for origins within their site (seeStoragePartitionImpl::CreateRestrictedCookieManager
). - Mojo serialization does not send any cookies from HTTP headers to the renderer
process (see
ParamTraits<scoped_refptr<net::HttpResponseHeaders>>::Write
).
Compromised renderers shouldn’t be able to read or write passwords of other sites.
Protection techniques:
- Using
CanAccessDataForOrigin
to verify IPCs sent by a renderer process (e.g.//components/password_manager/content/browser/bad_message.cc
) - Using trustworthy, browser-side knowledge
to determine which credentials to read or write
(e.g.
content::RenderFrameHost::GetLastCommittedURL
inpassword_manager::CredentialManagerImpl::GetOrigin
).
Compromised renderers shouldn’t be able to influence/spoof security-sensitive UI elements.
Examples:
- Omnibox
- URL (e.g. renderer process locked to foo.com shouldn’t be able to trick the Omnibox into displaying bar.com)
- Secure / not secure chip (e.g. a renderer process locked to a HTTP site shouldn’t be able to trick the Omnibox into displaying a HTTPS-associated lock)
- Content settings (e.g. a renderer process that has been granted microphone access shouldn’t be able to suppress the mic/camera icon in the Omnibox)
- Dialogs and prompts (for example a permissions dialog asking to allow
a site to show notifications)
- Origin in dialogs (e.g. a renderer process locked to foo.com shouldn’t be able to trick the Omnibox into displaying a bar.com URL in permission dialogs)
Protection techniques:
RenderFrameHostImpl::CanCommitOriginAndUrl
verifies that the renderer process is able to commit what it claims, and kills the process otherwise.- Work-in-progress: calculating the origin in the browser process, before a navigation commits (https://crbug.com/888079).
Compromised renderers shouldn’t be able to gain permissions without user consent.
Examples: microphone access permission, geolocation permission, etc.
Protection techniques:
- Requesting permissions based on browser-side knowledge of frame's origin
(e.g. see
GeolocationServiceImplContext::RequestPermission
).
Compromised renderers shouldn’t be able to read from or write into storage of another site.
Examples of protected storage technologies:
- localStorage
- sessionStorage
- indexedDB
- blob storage
- webSQL
Protection techniques:
- Using
CanAccessDataForOrigin
to verify IPCs sent by a renderer process (e.g. seeStoragePartitionImpl::OpenLocalStorage
). - Binding Mojo interfaces to a single origin obtained from browser-side
information in
RenderFrameHost::GetLastCommittedOrigin()
(e.g. seeRenderFrameHostImpl::CreateIDBFactory
).
Compromised renderers shouldn’t be able to:
- Spoof the
MessageEvent.origin
seen by a recipient of apostMessage
. - Bypass enforcement of the
targetOrigin
argument ofpostMessage
. - Send or receive
BroadcastChannel
messages for another origin. - Spoof the
MessageSender.origin
seen by a recipient of achrome.runtime.sendMessage
(see also MessageSender documentation and content script security guidance).
Protection techniques:
- Using
CanAccessDataForOrigin
to verify IPCs sent by a renderer process (e.g. inRenderFrameProxyHost::OnRouteMessageEvent
orBroadcastChannelProvider::ConnectToChannel
).
Known gaps in protection:
- Spoofing of
MessageSender.id
object (see the MessageSender documentation and https://crbug.com/982361).
Compromised renderers shouldn't be able to poison the JavaScript code cache used by scripts executed in cross-site execution contexts.
Protection techniques:
- Validating origins sent in IPCs from a renderer process by using
CanAccessDataForOrigin
inCodeCacheHostImpl::DidGenerateCacheableMetadataInCacheStorage
. - Using trustworthy, browser-side origin lock while writing to and fetching from
the code cache by using
ChildProcessSecurityPolicyImpl::GetOriginLock
inGetSecondaryKeyForCodeCache
in//content/browser/renderer_host/code_cache_host_impl.cc
A compromised renderer shouldn’t be able to bypass Cross-Origin-Resource-Policy (CORP), which prevents or allows responses from being requested cross-origin, more explicitly than CORB.
Protection techniques:
- Enforcing Cross-Origin-Resource-Policy in the NetworkService process (i.e. before the HTTP response is handed out to the renderer process).
- Preventing spoofing of
network::ResourceRequest::request_initiator
by usingnetwork::GetTrustworthyInitiator
which enforces browser-controlledrequest_initiator_origin_lock
.
A compromised renderer shouldn’t be able to bypass X-Frame-Options
or frame-ancestors
CSP.
For example, if example.com/page.html sends a X-Frame-Options: deny
header,
then it should never commit in a subframe, even if some renderers have
been compromised.
Protection techniques:
X-Frame-Options: deny
is enforced in the browser process viacontent::AncestorThrottle
, an implementation ofcontent::NavigationThrottle
.frame-ancestors
is enforced in a renderer process, but this process is considered trustworthy in this scenario (because it hosts the frame that is requesting protection). See also https://crbug.com/759184 which tracks moving this enforcement into the browser process.
Compromised renderers shouldn’t be able to control security sensitive HTTP
request headers like Host
or Sec-Fetch-Site
.
Protection techniques:
- Using
AreRequestHeadersSafe
to rejectHost
and other headers that should only be generated internally within the NetworkService. Sec-Fetch-Site
is robust against spoofing ofnetwork::ResourceRequest::request_initiator
by usingnetwork::GetTrustworthyInitiator
which enforces browser-controlledrequest_initiator_origin_lock
.
Known gaps in protection:
Origin
header. Tracked by https://crbug.com/920634 (makingnetwork::ResourceRequest::request_initiator
unspoofable without having to go throughGetTrustworthyInitiator
) and https://crbug.com/1098410 (removingnetwork::ResourceRequest::isolated_world_origin
which is used in some security decisions instead ofrequest_initiator
to support an allowlist of extensions that need to bypass CORB/CORS).
Compromised renderers shouldn’t be able to send a cross-site HTTP request with SameSite cookies.
Work-in-progress / not protected today.
TODO(morlovich): Add details. I assume that this requires trustworthy
|request_initiator| (similar to the Origin
header), but probably more
than that.
See also https://crbug.com/927967.
Compromised renderers shouldn't be able to spoof user gestures to perform actions requiring them:
-
A compromised renderer should not be able to forge a gesture that affects the trusted browser UI. For example, a compromised renderer should not be able to interact with the Omnibox or the WebBluetooth chooser.
-
A compromised renderer should not be able to forge a gesture that grants extra capabilities to a web origin. For example, a compromised renderer should not be able to open an unlimited number of popup windows by forging user gestures. Work-in-progress / not protected today - see https://crbug.com/848778.
Compromised non-extension renderers shouldn’t be able to access non-web-accessible-resources of a Chrome Extension.
Protection techniques:
- Navigations: Enforcement in the browser process
via
extensions::ExtensionNavigationThrottle
, an implementation ofcontent::NavigationThrottle
. This relies on non-spoofability ofcontent::NavigationHandle::GetInitiatorOrigin
. - Subresources: Enforcement in the browser process via
ExtensionURLLoaderFactory::CreateLoaderAndStart
. This relies on process boundaries and therefore doesn't rely on non-spoofability ofnetwork::ResourceRequest::request_initiator
.
Compromised web renderer processes shouldn’t be able to access
local resources (e.g. file://...
or chrome://settings
).
Protection techniques:
- TODO(lukasza, nasko): need to research
Due to resource constraints, on Android platforms only some sites get a dedicated renderer process, isolated from other sites. (Current heuristic is to isolate the sites where the user has entered a password in the past.) This means that some sites are hosted in a renderer process that is not locked to any particular site. If an attacker compromises an unlocked renderer process, they may try to abuse protection gaps listed below.
Known gaps in protection:
- When
CanAccessDataForOrigin
runs on the IO thread, it cannot protect isolated sites against being accessed from an unlocked renderer process. Some web storage protections depend onCanAccessDataForOrigin
calls on the IO thread. See also https://crbug.com/764958.
If an attacker could take control over the DevTools frontend then the attacker would gain access to all the cookies, storage, etc. of any origin within the page and would be able to execute arbitrary scripts in any frame of the page. This means that treating the DevTools renderer as untrustworthy wouldn't in practice offer additional protection for the same-origin-policy.
Because of the above:
- Chrome ensures that the DevTools frontend is always hosted in a renderer process separate from renderers hosting web origins.
- Chrome assumes that the DevTools frontend is always trustworthy (i.e. never compromised, or under direct control of an attacker). For example, when the DevTools process asks to initiate a HTTP request on behalf of https://example.com, the browser process trusts the DevTools renderer to claim authority to initiate requests of behalf of this origin (e.g. attach SameSite cookies, send appropriate Sec-Fetch-Site request header, etc.).