Lukasz Anforowicz | f4e58ce | 2020-05-11 18:18:58 | [diff] [blame^] | 1 | # Compromised Renderers |
| 2 | |
| 3 | Given the complexity of the browser, our threat model must use a "defense |
| 4 | in depth" approach to limit the damage that occurs if an attacker |
| 5 | finds a way around the Same Origin Policy or other security logic in the |
| 6 | renderer process. |
| 7 | For example, the combination of Chrome's sandbox, IPC security checks, and Site |
| 8 | Isolation limit what an untrustworthy renderer process can do. They |
| 9 | protect Chrome users against attackers, even when such attackers are able to |
| 10 | bypass security logic in the renderer process. |
| 11 | For other motivations for the "defense in depth" approach and why our |
| 12 | threat model covers compromised renderers, please see the |
| 13 | [document here](https://www.chromium.org/Home/chromium-security/site-isolation#TOC-Motivation). |
| 14 | |
| 15 | In a compromised renderer, an attacker is able to execute |
| 16 | arbitrary native (i.e. non-Javascript) code within the renderer |
| 17 | process's sandbox. A compromised renderer can forge |
| 18 | malicious IPC messages, impersonate a Chrome Extension content script, |
| 19 | or use other techniques to trick more privileged parts of the browser. |
| 20 | |
| 21 | The document below gives an overview of features that Chrome attempts to |
| 22 | protect against attacks from a compromised renderer. Newly discovered |
| 23 | holes in this protection would be considered security bugs and possibly |
| 24 | eligible for the |
| 25 | [Chrome Vulnerability Rewards Program](https://www.google.com/about/appsecurity/chrome-rewards/). |
| 26 | |
| 27 | [TOC] |
| 28 | |
| 29 | |
| 30 | ## Site Isolation foundations |
| 31 | |
| 32 | Most of the other protections listed in this document implicitly assume that |
| 33 | attacker-controlled execution contexts (e.g. HTML documents or service workers) |
| 34 | are hosted in a separate renderer process from other, victim contexts. |
| 35 | This separation is called |
| 36 | [Site Isolation](https://www.chromium.org/Home/chromium-security/site-isolation) |
| 37 | and allows the privileged browser |
| 38 | process to restrict what origins a renderer process is authorized to read or |
| 39 | control. |
| 40 | |
| 41 | The privilege restriction can be implemented in various ways - see the |
| 42 | "protection techniques" listed in other sections in this document. |
| 43 | One example is validating in the browser process whether an incoming IPC can |
| 44 | legitimately claim authority over a given origin (e.g. by checking via |
| 45 | `CanAccessDataForOrigin` if the process lock matches). |
| 46 | Another example is making sure that capabilities handed over to renderer |
| 47 | processes are origin-bound (e.g. by setting `request_initiator_site_lock` |
| 48 | on a `URLLoaderFactory` given to renderer processes). |
| 49 | Yet another example is making security decisions based on trustworthy knowledge, |
| 50 | calculated within the privileged browser process (e.g. using |
| 51 | `RenderFrameHost::GetLastCommittedOrigin()`). |
| 52 | |
| 53 | Compromised renderers shouldn’t be able to commit an execution context into a |
| 54 | renderer process hosting cross-site execution contexts. |
| 55 | On desktop platforms all sites (eTLD+1) should be isolated from each other. |
| 56 | On Android, sites where the user entered a password should be isolated |
| 57 | from each other and from other sites. |
| 58 | |
| 59 | **Known gaps in protection**: |
| 60 | - No form of Site Isolation is active in Android WebView |
| 61 | See also https://crbug.com/769449. |
| 62 | - No form of Site Isolation is active in content hosted within |
| 63 | `<webview>` HTML tags. See also https://crbug.com/614463. |
| 64 | - Frames with `<iframe sandbox>` attribute are not isolated |
| 65 | from their non-opaque precursor origin. |
| 66 | See also https://crbug.com/510122. |
| 67 | - `file:` frames may share a process with other `file:` frame. |
| 68 | See also https://crbug.com/780770. |
| 69 | |
| 70 | |
| 71 | ## Cross-Origin HTTP resources |
| 72 | |
| 73 | Compromised renderers shouldn't be able to read the contents (header + body) of |
| 74 | a cross-site HTTP response, unless it is a valid subresource needed for |
| 75 | compatibility (e.g., JavaScript, images, etc), or is successfully allowed via |
| 76 | CORS. |
| 77 | |
| 78 | Protection techniques: |
| 79 | - Enforcing |
| 80 | [Cross-Origin Read Blocking |
| 81 | (CORB)](https://www.chromium.org/Home/chromium-security/corb-for-developers) |
| 82 | in the NetworkService process |
| 83 | (i.e. before the HTTP response is handed out to the renderer process). |
| 84 | - Only allowing the privileged browser process to create |
| 85 | `network::mojom::URLLoaderFactory` objects that handle HTTP requests. |
| 86 | This lets the browser process carefully control security-sensitive |
| 87 | `network::mojom::URLLoaderFactoryParams` of such factories (such as |
| 88 | `request_initiator_site_lock`, `is_corb_enabled`, `disable_web_security` or |
| 89 | `isolation_info`). |
| 90 | This also lets the CORB implementation in the NetworkService process |
| 91 | prevent spoofing of `network::ResourceRequest::request_initiator` |
| 92 | by using `network::GetTrustworthyInitiator` for comparison with |
| 93 | the trustworthy `request_initiator_site_lock`. |
| 94 | |
| 95 | **Known gaps in protection**: |
| 96 | - Content types for which CORB does not apply |
| 97 | (e.g. `image/png`, `application/octet-stream`) are not protected by |
| 98 | default. We recommend that HTTP servers protect such resources by |
| 99 | either serving a `Cross-Origin-Resource-Policy: same-origin` response header |
| 100 | or validating the `Sec-Fetch-Site` request header. |
| 101 | - CORB protection is relaxed in presence of |
| 102 | - Adobe Flash plugin (see https://crbug.com/874515) |
| 103 | - A relatively small number of allowlisted Chrome Extensions |
| 104 | (see https://crbug.com/846346) |
| 105 | |
| 106 | |
| 107 | ## Contents of cross-site frames |
| 108 | |
| 109 | Compromised renderers shouldn't be able to read the contents of cross-site |
| 110 | frames. Examples: |
| 111 | - Text or pixels of cross-site frames. |
| 112 | - Full URL of cross-site frames. Note that the origin part is okay |
| 113 | since it is already exposed via `window.origin`. |
| 114 | |
| 115 | Protection techniques: |
| 116 | - Compositing tab contents (both for display and for printing) |
| 117 | outside the renderer processes. |
| 118 | - Isolating PDF plugins. |
| 119 | - Being careful what URLs are exposed in console messages. |
| 120 | |
| 121 | **Known gaps in protection**: |
| 122 | - Mixed content console messages may disclose cross-site URLs |
| 123 | (see also https://crbug.com/726178). |
| 124 | |
| 125 | |
| 126 | ## Cookies |
| 127 | |
| 128 | Compromised renderers shouldn’t be able to read or write |
| 129 | any cookies of another site, |
| 130 | or `httpOnly` cookies even from the same site. |
| 131 | |
| 132 | Protection techniques: |
| 133 | - Renderer processes are only given `network::mojom::RestrictedCookieManager` |
| 134 | for origins within their site |
| 135 | (see `StoragePartitionImpl::CreateRestrictedCookieManager`). |
| 136 | - Mojo serialization does not send any cookies from HTTP headers to the renderer |
| 137 | process (see |
| 138 | `ParamTraits<scoped_refptr<net::HttpResponseHeaders>>::Write`). |
| 139 | |
| 140 | |
| 141 | ## Passwords |
| 142 | |
| 143 | Compromised renderers shouldn’t be able to read or write passwords of |
| 144 | other sites. |
| 145 | |
| 146 | Protection techniques: |
| 147 | - Using `CanAccessDataForOrigin` to verify IPCs sent by a renderer process |
| 148 | (e.g. `//components/password_manager/content/browser/bad_message.cc`) |
| 149 | - Using trustworthy, browser-side knowledge |
| 150 | to determine which credentials to read or write |
| 151 | (e.g. `content::RenderFrameHost::GetLastCommittedURL` in |
| 152 | `password_manager::CredentialManagerImpl::GetOrigin`). |
| 153 | |
| 154 | |
| 155 | ## Security-sensitive UI/chrome elements (e.g. Omnibox) |
| 156 | |
| 157 | Compromised renderers shouldn’t be able to influence/spoof |
| 158 | security-sensitive UI elements. |
| 159 | |
| 160 | Examples: |
| 161 | - Omnibox |
| 162 | - URL (e.g. renderer process locked to foo.com shouldn’t |
| 163 | be able to trick the Omnibox into displaying bar.com) |
| 164 | - Secure / not secure chip (e.g. a renderer process locked to a HTTP |
| 165 | site shouldn’t be able to trick the Omnibox into displaying a |
| 166 | HTTPS-associated lock) |
| 167 | - Content settings (e.g. a renderer process that has been granted |
| 168 | microphone access shouldn’t be able to suppress the mic/camera |
| 169 | icon in the Omnibox) |
| 170 | - Dialogs and prompts (for example a permissions dialog asking to allow |
| 171 | a site to show notifications) |
| 172 | - Origin in dialogs (e.g. a renderer process locked to foo.com |
| 173 | shouldn’t be able to trick the Omnibox into displaying a bar.com |
| 174 | URL in permission dialogs) |
| 175 | |
| 176 | Protection techniques: |
| 177 | - `RenderFrameHostImpl::CanCommitOriginAndUrl` verifies that the renderer |
| 178 | process is able to commit what it claims, and kills the process otherwise. |
| 179 | - Work-in-progress: calculating the origin in the browser process, |
| 180 | before a navigation commits (https://crbug.com/888079). |
| 181 | |
| 182 | |
| 183 | ## Permissions |
| 184 | |
| 185 | Compromised renderers shouldn’t be able to gain permissions without user |
| 186 | consent. |
| 187 | |
| 188 | Examples: microphone access permission, geolocation permission, etc. |
| 189 | |
| 190 | Protection techniques: |
| 191 | - Requesting permissions based on browser-side knowledge of frame's origin |
| 192 | (e.g. see `GeolocationServiceImplContext::RequestPermission`). |
| 193 | |
| 194 | |
| 195 | ## Web storage |
| 196 | |
| 197 | Compromised renderers shouldn’t be able to read from or write into |
| 198 | storage of another site. |
| 199 | |
| 200 | Examples of protected storage technologies: |
| 201 | - localStorage |
| 202 | - sessionStorage |
| 203 | - indexedDB |
| 204 | - blob storage |
| 205 | - webSQL |
| 206 | |
| 207 | Protection techniques: |
| 208 | - Using CanAccessDataForOrigin to verify IPCs sent by a renderer process |
| 209 | (e.g. see `StoragePartitionImpl::OpenLocalStorage`). |
| 210 | - Binding mojo interfaces to a single origin obtained from browser-side |
| 211 | information in `RenderFrameHost::GetLastCommittedOrigin()` |
| 212 | (e.g. see RenderFrameHostImpl::CreateIDBFactory). |
| 213 | |
| 214 | **Known gaps in protection**: |
| 215 | - https://crbug.com/917457: FileSystem API (deprecated, Chrome-only). |
| 216 | |
| 217 | |
| 218 | ## Messaging |
| 219 | |
| 220 | Compromised renderers shouldn’t be able to: |
| 221 | - Spoof the `MessageEvent.origin` seen by a recipient of a `postMessage`. |
| 222 | - Bypass enforcement of the `targetOrigin` argument of `postMessage`. |
| 223 | - Send or receive BroadcastChannel messages for another origin. |
| 224 | - Spoof the `MessageSender.origin` seen by a recipient of a |
| 225 | `chrome.runtime.sendMessage` |
| 226 | (see also [MessageSender documentation](https://developers.chrome.com/extensions/runtime#type-MessageSender) and [content script security guidance](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/0ei-UCHNm34)). |
| 227 | |
| 228 | Protection techniques: |
| 229 | - Using CanAccessDataForOrigin to verify IPCs sent by a renderer process |
| 230 | (e.g. in `RenderFrameProxyHost::OnRouteMessageEvent` or |
| 231 | `BroadcastChannelProvider::ConnectToChannel`). |
| 232 | |
| 233 | **Known gaps in protection**: |
| 234 | - Spoofing of `MessageSender.id` object |
| 235 | (see [here](https://developers.chrome.com/extensions/runtime#type-MessageSender) |
| 236 | and https://crbug.com/982361). |
| 237 | |
| 238 | |
| 239 | ## Javascript code cache |
| 240 | |
| 241 | Compromised renderers shouldn't be able to poison the Javascript code cache |
| 242 | used by scripts executed in cross-site execution contexts. |
| 243 | |
| 244 | Protection techniques: |
| 245 | - Partitioning the code cache by Network Isolation Key (NIK). |
| 246 | - Using `CanAccessDataForOrigin` in |
| 247 | `CodeCacheHostImpl::DidGenerateCacheableMetadataInCacheStorage`. |
| 248 | |
| 249 | |
| 250 | ## Cross-Origin-Resource-Policy response header |
| 251 | |
| 252 | A compromised renderer shouldn’t be able to bypass |
| 253 | Cross-Origin-Resource-Policy (CORS), |
| 254 | which prevents or allows responses from being requested cross-origin, more |
| 255 | explicitly than CORB. |
| 256 | |
| 257 | Protection techniques: |
| 258 | - Enforcing Cross-Origin-Resource-Policy in the NetworkService process |
| 259 | (i.e. before the HTTP response is handed out to the renderer process). |
| 260 | - Preventing spoofing of `network::ResourceRequest::request_initiator` |
| 261 | by using `network::GetTrustworthyInitiator` which enforces |
| 262 | browser-controlled `request_initiator_site_lock`. |
| 263 | |
| 264 | |
| 265 | ## Frame-ancestors CSP and X-Frame-Options response headers |
| 266 | |
| 267 | A compromised renderer shouldn’t be able to bypass `X-Frame-Options` |
| 268 | or `frame-ancestors` CSP. |
| 269 | |
| 270 | For example, if example.com/page.html sends a `X-Frame-Options: deny` header, |
| 271 | then it should never commit in a subframe, even if some renderers have |
| 272 | been compromised. |
| 273 | |
| 274 | Protection techniques: |
| 275 | - `X-Frame-Options: deny` is enforced in the browser process |
| 276 | via `content::AncestorThrottle`, an implementation of |
| 277 | `content::NavigationThrottle`. |
| 278 | - `frame-ancestors` is enforced in a renderer process, but |
| 279 | this process is considered trustworthy in this scenario |
| 280 | (because it hosts the frame that is requesting protection). |
| 281 | See also https://crbug.com/759184 which tracks |
| 282 | moving this enforcement into the browser process. |
| 283 | |
| 284 | |
| 285 | ## HTTP request headers |
| 286 | |
| 287 | Compromised renderers shouldn’t be able to control security sensitive HTTP |
| 288 | request headers like `Host` or `Sec-Fetch-Site`. |
| 289 | |
| 290 | Protection techniques: |
| 291 | - Using `AreRequestHeadersSafe` to reject `Host` and other headers that |
| 292 | should only be generated internally within the NetworkService. |
| 293 | - `Sec-Fetch-Site` is robust against spoofing of |
| 294 | `network::ResourceRequest::request_initiator` by using |
| 295 | `network::GetTrustworthyInitiator` which enforces browser-controlled |
| 296 | `request_initiator_site_lock`. |
| 297 | |
| 298 | **Known gaps in protection**: |
| 299 | - `Origin` header. Tracked by |
| 300 | https://crbug.com/920634 (making |
| 301 | `network::ResourceRequest::request_initiator` unspoofable without |
| 302 | having to go through `GetTrustworthyInitiator`) and |
| 303 | https://crbug.com/920638 (making |
| 304 | `network::ResourceRequest::isolated_world_origin` irrelevant for |
| 305 | security decisions). |
| 306 | |
| 307 | |
| 308 | ## (WIP) SameSite cookies |
| 309 | |
| 310 | Compromised renderers shouldn’t be able to send a cross-site HTTP request with |
| 311 | SameSite cookies. |
| 312 | |
| 313 | **Work-in-progress / not protected today**. |
| 314 | |
| 315 | TODO(morlovich): Add details. I assume that this requires trustworthy |
| 316 | |request_initiator| (similar to the `Origin` header), but probably more |
| 317 | than that. |
| 318 | |
| 319 | See also https://crbug.com/927967. |
| 320 | |
| 321 | |
| 322 | ## (WIP) User gestures / activations. |
| 323 | |
| 324 | Compromised renderers shouldn't be able to spoof user gestures to perform |
| 325 | actions requiring them. |
| 326 | |
| 327 | **Work-in-progress / not protected today**. See https://crbug.com/848778. |
| 328 | |
| 329 | |
| 330 | ## Web Accessible Resources of Chrome Extensions |
| 331 | |
| 332 | Compromised non-extension renderers shouldn’t be able to access |
| 333 | non-web-accessible-resources of a Chrome Extension. |
| 334 | |
| 335 | Protection techniques: |
| 336 | - Navigations: Enforcement in the browser process |
| 337 | via `extensions::ExtensionNavigationThrottle`, an implementation of |
| 338 | `content::NavigationThrottle`. This relies on non-spoofability |
| 339 | of `content::NavigationHandle::GetInitiatorOrigin`. |
| 340 | - Subresources: Enforcement in the browser process via |
| 341 | `ExtensionURLLoaderFactory::CreateLoaderAndStart`. This relies |
| 342 | on process boundaries and therefore doesn't rely on non-spoofability |
| 343 | of `network::ResourceRequest::request_initiator`. |
| 344 | |
| 345 | |
| 346 | ## Non-Web resources |
| 347 | |
| 348 | Compromised *web* renderer processes shouldn’t be able to access |
| 349 | *local* resources (e.g. `file://...` or `chrome://settings`). |
| 350 | |
| 351 | Protection techniques: |
| 352 | - TODO(lukasza, nasko): need to research |
| 353 | |
| 354 | |
| 355 | ## Android-specific protection gaps |
| 356 | |
| 357 | Due to resource constraints, on Android platforms only some sites get a |
| 358 | dedicated renderer process, isolated from other sites. |
| 359 | (Current heuristic is to isolate the sites where the user has entered a password |
| 360 | in the past.) |
| 361 | This means that some sites are hosted in a renderer process that is |
| 362 | *not* locked to any particular site. If an attacker compromises |
| 363 | an unlocked renderer process, they may try to abuse protection gaps listed |
| 364 | below. |
| 365 | |
| 366 | **Known gaps in protection**: |
| 367 | - When `CanAccessDataForOrigin` runs on the IO thread, it cannot protect |
| 368 | isolated sites against being accessed from an unlocked renderer process. |
| 369 | Some web storage protections depend on `CanAccessDataForOrigin` calls |
| 370 | on the IO thread. |
| 371 | See also https://crbug.com/764958. |
| 372 | - `request_initiator_site_lock` may be missing in unlocked renderer |
| 373 | processes on Android (for example affecting protections of CORB, CORP, |
| 374 | Sec-Fetch-Site and in the future SameSite cookies and Origin |
| 375 | protections). See also https://crbug.com/891872. |