| # Connection Allowlist Design |
| |
| References: |
| * [Explainer][1] |
| * [Spec][2] |
| * [Chrome Status Entry][3] |
| * [Design Document][4] |
| |
| ## Summary |
| |
| Connection Allowlist restricts network connections in Chromium using a |
| URLPattern allowlist returned by the server. The high-level flow is: |
| |
| * The allowlist is returned in the HTTP response when loading a given |
| context (document or worker) |
| * A `network_restrictions_id` is assigned to that context, which is used to |
| identify requests that originate from it |
| * Enforcement then focuses on blocking requests containing that ID based on |
| the mapped allowlist. |
| |
| This document outlines the architectural design and the checks performed |
| across different Chromium layers (network service, browser, renderer). |
| |
| All security and resource restrictions (CSP, Connection Allowlists, etc.) are |
| applied **restrictively and additively**. A request must satisfy **all** |
| applicable security policies to proceed; if any policy blocks the request, the |
| request is blocked. |
| |
| ## Design |
| |
| ### Network service integration |
| |
| The network service is the primary layer where network requests are handled and |
| dispatched. The majority of Connection Allowlist enforcement occurs here. |
| * **Responsibilities:** |
| * Intercept and filter outgoing network requests. |
| * Apply allowlist rules at the URLLoader level (including document-initiated |
| prefetches which are associated with the document's |
| `network_restrictions_id`). |
| * Enforce allowlists for other networking APIs like WebSockets, DNS Prefetch, |
| and WebTransport. |
| * **Benefits:** |
| * **Defense-in-Depth:** Since enforcement occurs in the Network Service |
| process, compromised renderer processes cannot bypass these checks. |
| * **Centralized Enforcement:** The Network Service handles HTTP/HTTPS |
| requests, WebSockets, and WebTransport. Enforcing allowlists at this level |
| provides a single, uniform point of control across different network |
| protocols. |
| * **Semantic Consistency:** Once registered, allowlist matching happens |
| within the Network Service process. This ensures that the same set of |
| rules is applied to all requests regardless of where they originated |
| (e.g. fetch, fetch redirects, prefetch, worker, etc.). |
| * **Extensibility:** The token-based mapping (`network_restrictions_id`) is |
| highly extensible. Other future security features or JS-based network |
| restriction APIs (similar to the dynamic |
| `window.fence.disableUntrustedNetwork()` design previously used for Fenced |
| Frames, see [CL 7709872][5]) can leverage this same plumbing to dynamically |
| register and enforce rules in the Network Service. |
| |
| #### Network restrictions ID (`network_restrictions_id`) |
| |
| To map network requests back to the corresponding context (document or worker) |
| and its connection allowlists, each context is associated with a unique token, |
| the `network_restrictions_id` (a `base::UnguessableToken`). |
| |
| * **Creation & Propagation**: |
| * During cross-document navigation, a new `network_restrictions_id` is |
| created on the `NavigationRequest` in |
| `NetworkRestrictionsNavigationThrottle`. |
| * Upon navigation commit, this ID is wrapped in a ref-counted handle |
| (`base::RefCountedData<base::UnguessableToken>`) and stored in the |
| document's `DocumentAssociatedData` (or worker hosts like |
| `DedicatedWorkerHost` and `SharedWorkerHost`). |
| * Ref-counting is used because there are edge cases where multiple documents |
| can share the same `network_restrictions_id` (e.g., initial empty documents |
| inheriting their creator's ID). |
| * **Updating the Network Service**: |
| * If a document has active connection allowlists (enforced or report-only) |
| determined from policy container policies, the browser process registers |
| them via `StoragePartitionImpl::RestrictNetworkForIdsInNetworkContext`. |
| * This sends the ID and allowlisted patterns to the `NetworkContext` in the |
| Network Service using `RestrictNetworkForIds()`. |
| * The navigation is deferred during the throttle check |
| (`WillProcessResponse` / `WillCommitWithoutUrlLoader`) until the Network |
| Service confirms the restrictions have been registered, ensuring |
| restrictions are applied before resource loading begins. |
| * **Backup & Recovery**: |
| * `StoragePartitionImpl` stores a copy of the restrictions in |
| `network_restrictions_ids_`. In case of a Network Service crash, this map |
| is used to restore the network restrictions on the new `NetworkContext`. |
| * **Lifetime & Cleanup**: |
| * When a document's `DocumentAssociatedData` or worker is destroyed, if it |
| holds the last reference to the ref-counted `network_restrictions_id`, it |
| schedules a cleanup of the restriction mapping from the Network Service |
| and `StoragePartitionImpl` using |
| `StoragePartitionImpl::ClearNetworkRestrictionsAfterDelay`. |
| * **Selecting the ID at Calling Sites**: |
| When a calling site initiates a request or creates a connection (e.g. |
| WebSocket, WebTransport) that expects a `network_restrictions_id`, it |
| should use: |
| * **The context's ID**: If the request/connection is associated with a |
| specific context (document, dedicated worker, shared worker, or service |
| worker), use that context's `network_restrictions_id`. |
| * **`network::GetNoOpNetworkRestrictionsId()`**: When no network |
| restrictions should be applied, bypassing restrictions entirely. This |
| should be used carefully as it bypasses the Connection Allowlist (e.g., |
| for browser-initiated requests that do not have an associated |
| frame/context). |
| * **`network::GetTestNetworkRestrictionsId()`**: In tests that require a |
| valid network restrictions ID but do not test Connection Allowlist |
| behavior. |
| |
| ### Browser process checks (content/browser) |
| |
| The browser process coordinates navigation checks and handles security |
| policies. |
| * **Responsibilities:** |
| * Store and manage Connection Allowlists as part of the `PolicyContainerHost` |
| associated with each document. |
| * Intercept and validate navigations in the browser process before they are |
| sent to the network service using the |
| `NavigationRequest::IsAllowedByConnectionAllowlist` function. This function |
| enforces allowlist policies during key phases of navigation (such as |
| initial request start and handling redirects). |
| |
| ### Blink checks |
| |
| Blink is the rendering engine running in the renderer process. |
| * **Responsibilities:** |
| * Enforce Connection Allowlists in the renderer process for: |
| 1. WebRTC connections. These checks are also validated in the network |
| service to handle compromised renderers. |
| 2. Requests initiated via `fetch()` when they will be intercepted by a |
| Service Worker. This is done in blink because the renderer directly |
| talks to the Service Worker URLLoaderFactory in these cases, not giving |
| the document's URLLoaderFactory checks a chance to run, unless the SW |
| decides to fallback on the original fetch. This applies when the |
| initiating context is either a document, dedicated worker or shared |
| worker. |
| |
| ### Integration with service workers |
| Service Workers act as network proxies in the renderer process, intercepting |
| requests before they reach the network. |
| * **Responsibilities:** |
| * **Main Script Fetches & Update Checks**: Subject Service Worker main script |
| fetches and update checks to the Connection Allowlists of the |
| **creator/initiator context**(the registering document). |
| * **Initial Install**: The browser process creates the loader factory via |
| `GetLoaderFactoryForMainScriptFetch` passing the |
| `creator_network_restrictions_id_`. |
| * **Update Checks**: During soft update checks (in |
| `ServiceWorkerRegisterJob::UpdateAndContinue`), the loader factory is |
| created via `GetLoaderFactoryForUpdateCheck` passing the |
| `creator_network_restrictions_id_`. |
| * **Intercepted Document Fetches**: Ensure requests initiated by a document |
| that are intercepted by a Service Worker are validated in Blink against the |
| **document's** Connection Allowlists before they are forwarded to the |
| Service Worker. This prevents documents from bypassing their own |
| restrictions, including when the Service Worker attempts to serve |
| responses from Cache Storage. |
| * **Service Worker Outgoing Fetches**: Apply the Service Worker's own |
| Connection Allowlists (persisted and restored via the database) to its |
| own fetches. |
| * Requests initiated directly by the Service Worker context |
| (`ServiceWorkerGlobalScope`) itself (via `fetch()`) are governed by the |
| policies stored in its own `PolicyContainerHost`. Those are mapped to |
| the Service Worker's own `network_restrictions_id` in the Network |
| Service via the `NetworkRestrictionsWorkerThrottle`. This throttle also |
| does the same for dedicated and shared worker contexts. |
| * Once a request is inside the Service Worker, any outgoing network |
| fetches (e.g., via `event.respondWith(fetch(request))`) are initiated |
| using the Service Worker's `URLLoaderFactory` and subjected to the |
| **Service Worker's** Connection Allowlists (associated with the Service |
| Worker's own `network_restrictions_id`), regardless of the client |
| document's policies. Consequently, redirects of these fetches are |
| checked against the Service Worker's connection allowlist's redirect |
| flag, not the document's. |
| * **Navigation Preload**: Navigation preload requests are subject to the |
| **Service Worker's** Connection-Allowlist. If the navigation itself is |
| allowed by the document's Connection-Allowlist, the associated navigation |
| preload request will be executed using the Service Worker's |
| `URLLoaderFactory` (which is associated with the Service Worker's |
| `network_restrictions_id`), thereby enforcing the Service Worker's |
| policies. |
| * **clients.navigate() in Service Workers**: Navigation initiated via |
| clients.navigate() is subject to both the Service Worker's and the |
| document's Connection Allowlists. Since the navigation is initiated from |
| the Service Worker context, the Service Worker's Connection Allowlists |
| apply to the navigation before it is initiated from the Service Worker. |
| In addition, since the navigation is on a window client (which has an |
| associated Document), the Document's Connection Allowlists also apply, |
| and if there is a server redirect, the document's Connection Allowlists' |
| redirect bit will be checked. |
| * **clients.openWindow() in Service Workers**: Navigation initiated via |
| clients.openWindow() is subject to the Service Worker's Connection |
| Allowlists before it is initiated. There is no check on redirect since |
| there is no CA to be checked once the navigation has started. |
| |
| [1]: https://github.com/WICG/connection-allowlists |
| [2]: https://wicg.github.io/connection-allowlists/ |
| [3]: https://chromestatus.com/feature/5175745573945344 |
| [4]: https://docs.google.com/document/d/1B3LERUObjVDAKBNLpdIxbk8LC96rWUn1q8vtP9pPIuA/edit?usp=sharing |
| [5]: https://chromium-review.googlesource.com/c/chromium/src/+/7709872 |