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.
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:
<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 other file:
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:
network::mojom::URLLoaderFactory
objects that handle HTTP requests. This lets the browser process carefully control security-sensitive network::mojom::URLLoaderFactoryParams
of such factories (such as request_initiator_origin_lock
, is_orb_enabled
, disable_web_security
or isolation_info
).Known gaps in protection:
image/png
, application/octet-stream
) are not protected by default. We recommend that HTTP servers protect such resources by either serving a Cross-Origin-Resource-Policy: same-origin
response header or validating the Sec-Fetch-Site
request header.Compromised renderers shouldn't be able to read the contents of cross-site frames. Examples:
window.origin
for legacy reasons.Protection techniques:
Known gaps in protection:
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:
network::mojom::RestrictedCookieManager
for origins within their site (see StoragePartitionImpl::CreateRestrictedCookieManager
).ParamTraits<scoped_refptr<net::HttpResponseHeaders>>::Write
).Compromised renderers shouldn’t be able to read or write passwords of other sites.
Protection techniques:
CanAccessDataForOrigin
to verify IPCs sent by a renderer process (e.g. //components/password_manager/content/browser/bad_message.cc
)content::RenderFrameHost::GetLastCommittedURL
in password_manager::CredentialManagerImpl::GetOrigin
).Compromised renderers shouldn’t be able to influence/spoof security-sensitive UI elements.
Examples:
Protection techniques:
RenderFrameHostImpl::CanCommitOriginAndUrl
verifies that the renderer process is able to commit what it claims, and kills the process otherwise.Compromised renderers shouldn’t be able to gain permissions without user consent.
Examples: microphone access permission, geolocation permission, etc.
Protection techniques:
GeolocationServiceImplContext::RequestPermission
).Compromised renderers shouldn’t be able to read from or write into storage of another site.
Examples of protected storage technologies:
Protection techniques:
CanAccessDataForOrigin
to verify IPCs sent by a renderer process (e.g. see StoragePartitionImpl::OpenLocalStorage
).RenderFrameHost::GetLastCommittedOrigin()
(e.g. see RenderFrameHostImpl::CreateIDBFactory
).Compromised renderers shouldn’t be able to:
MessageEvent.origin
seen by a recipient of a postMessage
.targetOrigin
argument of postMessage
.BroadcastChannel
messages for another origin.MessageSender.url
, nor MessageSender.origin
, nor MessageSender.id
(i.e. an extension id which can differ from the origin when the message is sent from a content script), as seen by a recipient of a chrome.runtime.sendMessage
. See also MessageSender documentation and content script security guidance.Protection techniques:
CanAccessDataForOrigin
to verify IPCs sent by a renderer process (e.g. in RenderFrameProxyHost::OnRouteMessageEvent
or BroadcastChannelProvider::ConnectToChannel
).ContentScriptTracker
to check if IPCs from a given renderer process can legitimately claim to act on behalf content scripts of a given extension.Compromised renderers shouldn't be able to poison the JavaScript code cache used by scripts executed in cross-site execution contexts.
Protection techniques:
ChildProcessSecurityPolicyImpl::GetOriginLock
in GetSecondaryKeyForCodeCache
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:
network::ResourceRequest::request_initiator
by comparing against request_initiator_origin_lock
in network::CorsURLLoaderFactory::IsValidRequest
.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 via content::AncestorThrottle
, an implementation of content::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
, Origin
, or Sec-Fetch-Site
.
Protection techniques:
AreRequestHeadersSafe
to reject Host
and other headers that should only be generated internally within the NetworkService.network::ResourceRequest::request_initiator
by comparing against request_initiator_origin_lock
in network::CorsURLLoaderFactory::IsValidRequest
.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:
extensions::ExtensionNavigationThrottle
, an implementation of content::NavigationThrottle
. This relies on non-spoofability of content::NavigationHandle::GetInitiatorOrigin
.ExtensionURLLoaderFactory::CreateLoaderAndStart
. This relies on process boundaries and therefore doesn't rely on non-spoofability of network::ResourceRequest::request_initiator
.Compromised web renderer processes shouldn’t be able to access local resources (e.g. file://...
or chrome://settings
).
Protection techniques:
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:
CanAccessDataForOrigin
runs on the IO thread, it cannot protect isolated sites against being accessed from an unlocked renderer process. Some web storage protections depend on CanAccessDataForOrigin
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: