Local Network Access

Draft Community Group Report,

This version:
https://wicg.github.io/local-network-access/
Issue Tracking:
GitHub
Inline In Spec
Editor:
(Google)
Former Editor:
(Google)

Abstract

This document specifies modifications to Fetch and HTML which are intended to mitigate the risks associated with unintentional exposure of devices and servers on a client’s internal network to the web at large.

This specification was previously known as CORS-RFC1918.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

1. Introduction

This section is not normative.

Although [RFC1918] has specified a distinction between "private" and "public" internet addresses for over two decades, user agents haven’t made much progress at segregating the one from the other. Websites on the public internet can make requests to internal devices and servers, which enable a number of malicious behaviors, including attacks on users' routers like those documented in [DRIVE-BY-PHARMING], [SOHO-PHARMING] and [CSRF-EXPLOIT-KIT].

Here, we propose a mitigation against these kinds of attacks that would require internal devices to explicitly opt-in to requests from the public internet.

1.1. Goals

The overarching goal is to prevent the user agent from inadvertently enabling attacks on devices running on a user’s local intranet, or services running on the user’s machine directly. For example, we wish to mitigate attacks on:

1.2. Examples

1.2.1. Secure by Default

MegaCorp Inc’s routers have a fairly serious CSRF vulnerability which allows their DNS settings to be altered by navigating to http://admin:admin@router.local/set_dns and passing in various GET parameters. Oh noes!

Happily, MegaCorp Inc’s routers don’t have any interest in requests from the public internet, and didn’t take any special effort to enable them. This greatly mitigates the scope of the vulnerability, as malicious requests will generate a CORS-preflight request, which the router ignores. Let’s take a closer look:

Given https://csrf.attack/ that contains the following HTML:

<iframe href="https://admin:admin@router.local/set_dns?server1=123.123.123.123">
</iframe>

router.local will be resolved to the router’s address via the magic of multicast DNS [RFC6762], and the user agent will note it as local. Since csrf.attack resolved to a public address, the request will trigger a CORS-preflight request:

OPTIONS /set_dns?... HTTP/1.1
Host: router.local
Access-Control-Request-Method: GET
Access-Control-Request-Local-Network: true
...
Origin: https://csrf.attack

The router will receive this OPTIONS request, and has a number of possible safe responses:

  • If it doesn’t understand OPTIONS at all, it can return a 50X error. This will cause the preflight to fail, and the actual GET will never be issued.

  • If it does understand OPTIONS, it can neglect to include an Access-Control-Allow-Local-Network header in its response. This will cause the preflight to fail, and the actual GET will never be issued.

  • It can crash. Crashing is fairly safe, if inelegant.

1.2.2. Opting-In

Some of MegaCorp Inc’s devices actually need to talk to the public internet for various reasons. They can explicitly opt-in to receiving requests from the internet by sending proper CORS headers in response to a CORS-preflight request.

When a website on the public internet makes a request to the device, the user agent determines that the requestor is public, and the router is local. This means that requests will trigger a CORS-preflight request, just as above.

The device can explicitly grant access by sending the right headers in its response to the preflight request. For the above request, that might look like:

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://public.example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Local-Network: true
Content-Length: 0
...
MegaCorp Inc. runs an internal link shortening service at https://go/, and its employees often email such links to each other. The email server is hosted at a public address in order to ensure that employees can work even when they’re not at the office. How considerate!

Clicking https://go/* links from https://mail.mega.corp/ will trigger a CORS-preflight request, as it is a request from a public address to a local address:

OPTIONS /short-links-are-short-after-shortening HTTP/1.1
Host: go
Access-Control-Request-Method: GET
Access-Control-Request-Local-Network: true
...
Origin: https://mail.mega.corp

In order to ensure that employees can continue to navigate such links as expected, MegaCorp chooses to allow local network requests:

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://mail.mega.corp
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Local-Network: true
Content-Length: 0
...

MegaCorp’s leak-prevention department is worried, though, that this access will allow external folks to read the location of any redirect that the shortener would return. They’re more or less resigned to the fact that https://go/shortlink will leak, but would be sad indeed if the target (https://sekrits/super-sekrit-project-with-super-sekrit-partner) leaked as well.

MegaCorp’s shortlink engineers are careful to avoid this potential failure by returning CORS headers only for the preflight. The "real" navigation doesn’t require CORS headers, and they don’t actually want to support cross-origin requests as being CORS-same-origin:

// Request:
GET /short-links-are-short-after-shortening HTTP/1.1
Host: go
...

// Response:
HTTP/1.1 301 Moved Permanently
...
Location: https://sekrits/super-sekrit-project-with-super-sekrit-partner

The navigation will proceed normally, but mail.mega.corp won’t be considered CORS-same-origin with the response.

2. Framework

2.1. IP Address Space

Every IP address belongs to an IP address space, which can be one of three different values:

  1. loopback: contains the local host only. In other words, addresses whose target differs for every device.

  2. local: contains addresses that have meaning only within the current network. In other words, addresses whose target differs based on network position.

  3. public: contains all other addresses. In other words, addresses whose target is the same for all devices globally on the IP network.

For convenience, we additionally define the following terms:

  1. A loopback address is an IP address whose IP address space is loopback.

  2. A local address is an IP address whose IP address space is local.

  3. A public address is an IP address whose IP address space is public.

An IP address space lhs is less public than an IP address space rhs if any of the following conditions holds true:

  1. lhs is loopback and rhs is either local or public.

  2. lhs is local and rhs is public.

To determine the IP address space of an IP address address, run the following steps:

  1. If address belongs to the ::ffff:0:0/96 "IPv4-mapped Address" address block, then replace address with its embedded IPv4 address.

  2. For each row in the Non-public IP address blocks" table:

    1. If address belongs to row’s address block, return row’s address space.

  3. Return public.

Non-public IP address blocks
Address block Name Reference Address space
127.0.0.0/8 IPv4 Loopback [RFC1122] loopback
10.0.0.0/8 Private Use [RFC1918] local
100.64.0.0/10 Carrier-Grade NAT [RFC6598] local
172.16.0.0/12 Private Use [RFC1918] local
192.168.0.0/16 Private Use [RFC1918] local
169.254.0.0/16 Link Local [RFC3927] local
::1/128 IPv6 Loopback [RFC4291] loopback
fc00::/7 Unique Local [RFC4193] local
fe80::/10 Link-Local Unicast [RFC4291] local
::ffff:0:0/96 IPv4-mapped [RFC4291] see mapped IPv4 address

User Agents MAY allow certain IP address blocks' address space to be overridden through administrator or user configuration. This could prove useful to protect e.g. IPv6 intranets where most IP addresses are considered public per the algorithm above, by instead configuring user agents to treat the intranet as local.

Note: Link-local IP addresses such as 169.254.0.0/16 are considered local, since such addresses can identify the same target for all devices on a network link. A previous version of this specification considered them to be loopback instead.

Note: The contents of each IP address space were at one point determined in accordance with the IANA Special-Purpose Address Registries ([IPV4-REGISTRY] and [IPV6-REGISTRY]) and the Globally Reachable bit defined therein. This turned out to be an inaccurate signal for our uses, as described in spec issue #50.

Remove the special case for IPv4-mapped IPv6 addresses once access to these addresses is blocked entirely. [Issue #36]

2.2. Local Network Request

A request (request) is a local network request if request’s current url's host maps to an IP address whose IP address space is less public than request’s policy container's IP address space.

The classification of IP addresses into three broad address spaces is an imperfect and theoretically-unsound approach. It is a proxy used to determine whether two network endpoints should be allowed to communicate freely or not, in other words whether endpoint A is reachable from endpoint B without pivoting through the user agent on endpoint C.

This approach has some flaws:

Even so, this specification aims to offer a pragmatic solution to a security issue that broadly affects most users of the Web whose network configurations are not so complex.

The definition of local network requests could be expanded to cover all cross-origin requests for which the current url's host maps to an IP address whose IP address space is not public. This would prevent a malicious server on the local network from attacking other servers. The effort require to ship such a change is not deemed worth the payoff for now. This can be shipped as an incremental improvement later on. [Issue #39]

NOTE: Some local network requests are more challenging to secure than others. See § 4.4 Rollout difficulties for more details.

2.3. Additional CORS Headers

The Access-Control-Request-Local-Network indicates that the request is a local network request.

The Access-Control-Allow-Local-Network indicates that a resource can be safely shared with external networks.

Note: Previous versions of this spec spelled the headers as Access-Control-Request-Private-Network and Access-Control-Allow-Private-Network.

2.4. The treat-as-public-address Content Security Policy Directive

The treat-as-public-address directive instructs the user agent to treat a document as though it was served from a public address, even if it was actually served from a local address or a loopback address. That is, it is a mechanism by which non-public documents may drop the privilege to contact other non-public documents without a preflight.

The directive’s syntax is described by the following ABNF grammar:

directive-name  = "treat-as-public-address"
directive-value = ""

This directive has no reporting requirements; it will be ignored entirely when delivered in a Content-Security-Policy-Report-Only header, or within a meta element.

This directive’s initialization algorithm is as follows. Given an environment settings object (context), a Response (response), and a policy (policy):

  1. Set context’s policy container's IP address space to public if policy’s disposition is "enforce".

2.5. Feature Detection

A previous version of this specification proposed adding an addressSpace enum property to Document and WorkerGlobalScope, but it was removed due to fingerprinting concerns (see issue #21).

Documents should not behave differently or not based on whether the UA implements this specification or not - all documents should assume it does.

3. Integrations

This section is non-normative.

This document proposes a number of modifications to other specifications in order to implement the mitigations sketched out in the examples above. These integrations are outlined here for clarity, but the external documents are the normative references.

3.1. Integration with Fetch

This document proposes a few changes to Fetch, with the following implication: local network requests are only allowed if their client is a secure context and a CORS-preflight request to the target origin is successful.

Note: This includes navigations. These can indeed be used to trigger CSRF attacks, albeit with less subtlety than with subresource requests.

Note: [FETCH] does not yet integrate the details of DNS resolution into the Fetch algorithm, though it does define an obtain a connection algorithm which is enough for this specification. Local Network Access checks are applied to the newly-obtained connection. Given complexities such as Happy Eyeballs ([RFC6555], [RFC8305]), these checks might pass or fail non-deterministically for hosts with multiple IP addresses that straddle IP address space boundaries.

3.1.1. Secure context restriction

UAs must not allow non-secure public contexts to request resources from local addresses, even if the local server would opt-in to such a request via a preflight. Making requests to local resources presents risks which are mitigated by ensuring the integrity of the client which initiates the request. In particular, network attackers should not be able to trivially exploit an endpoint’s consent to a non-secure origin.

To that end:

  1. Connection objects are given a new IP address space property, initially null. This applies to WebSocket connections too.

  2. A new step is added to the obtain a connection algorithm immediately before appending connection to the user agent’s connection pool:

    1. Set connection’s IP address space to the result of running the determine the IP address space algorithm on the IP address of connection’s remote endpoint.

      The remote endpoint concept is not specified in [FETCH] yet, hence this is still handwaving to some extent. [Issue #33]

  3. Response objects are given a new IP address space property, whose value is an IP address space, initially null.

  4. Define a new Local Network Access check algorithm. Given a request request and a connection connection:

    1. If request’s origin is a potentially trustworthy origin and request’s current URL’s origin is same origin with request’s origin, then return null.

    2. If request’s client is a non-secure context:

      1. Let clientAddressSpace be request’s policy container's IP address space.

      2. If connection’s IP address space is less public than clientAddressSpace, then return a network error.

    3. Return null.

  5. The HTTP-network fetch algorithm is amended to add 3 new steps right after checking that the newly-obtained connection is not failure:

    1. Set response’s IP address space to connection’s IP address space.

    2. Let localNetworkAccessCheckResult be the result of running Local Network Access check for fetchParamsrequest and connection.

    3. If localNetworkAccessCheckResult is a network error, return localNetworkAccessCheckResult.

3.1.2. CORS preflight

The HTTP fetch algorithm should be adjusted to ensure that a preflight is triggered for all local network requests initiated from secure contexts.

The main issue here is again that the response’s IP address space is not known until a connection is obtained in HTTP-network fetch, which is layered under CORS-preflight fetch. What follows is a sketch of a potential solution:

  1. Add a new target IP address space property to the request struct, initially null.

  2. Amend the Local Network Access check algorithm to handle this new property and propagate the IP address space of the newly-obtained connection to the caller of the HTTP-network fetch algorithm when the client is a secure context:

    1. If request’s target IP address space is not null, then:

      1. If connection’s IP address space is not equal to then request’s target IP address space, then return a network error.

      2. Return null.

    2. Let clientAddressSpace be request’s policy container's IP address space.

    3. If response’s IP address space is less public than clientAddressSpace, then:

      1. Let error be a network error.

      2. If request’s client is a secure context, then set error’s IP address space property to response’s IP address space.

      3. Return error.

    4. Return null.

  3. Define a new algorithm called HTTP-no-service-worker fetch based on the existing steps in HTTP fetch that are run if response is still null after handling the fetch via service workers, and amend those slightly as follows:

    1. At the very start:

      1. If request’s target IP address space is not null, then set makeCORSPreflight to true.

    2. Immediately after running CORS-preflight fetch:

      1. If preflightResponse is a network error:

        1. If preflightResponse’s IP address space is null, return preflightResponse.

        2. Set request’s target IP address space to preflightResponse’s IP address space.

        3. Return the result of running HTTP-no-service-worker fetch given fetchParams.

    3. Immediately after running HTTP-network-or-cache fetch:

      1. If response is a network error and response’s IP address space is non-null, then:

        1. Set request’s target IP address space to preflightResponse’s IP address space.

        2. Return the result of running HTTP-no-service-worker fetch given fetchParams.

    Note: Because request’s target IP address space is set to a non-null value when recursing, this recursion can go at most 1 level deep.

  4. The CORS-preflight fetch algorithm is adjusted to handle the new headers:

    1. Immediately before running HTTP-network-or-cache fetch:

      1. If request’s target IP address space is not null, then:

        1. Set "Access-Control-Request-Local-Network" to "true" in preflight’s header list.

    2. Immediately after the CORS check:

      1. If request’s target IP address space is not null, then:

        1. Let allow be the result of extracting header list values given "Access-Control-Allow-Local-Network" and response’s header list.

        2. If allow is not "true", return a network error.

  5. Finally, to mitigate the impact of DNS rebinding attacks (see § 5.3 DNS Rebinding), the CORS-preflight cache is adjusted to take IP address space information into account:

    1. A new IP address space property (null or an IP address space) is added to each cache entry.

    2. This new property is initialized by the create a new cache entry algorithm from request’s target IP address space.

    3. This new property is checked by the cache entry match algorithm:

      1. entry’s IP address space is equal to request’s target IP address space.

3.1.3. Forbidden header names

A new entry is added to the list of forbidden header names: Access-Control-Request-Local-Network.

The user agent should have full control over this header, just as it does over other CORS headers.

3.2. Integration with WebSockets

Preflight requests should probably be sent ahead of WebSocket handshakes, given that WebSocket handshakes have roughly the same capabilities as <img> tags. This might require no additional work to specify given that the establish a WebSocket connection depends on the Fetch algorithm. [Issue #14]

A previous version of this specification proposed simply adding the new headers (see § 2.3 Additional CORS Headers) to the WebSocket handshake. This would not be sufficient to fully guard against CSRF attacks, however.

3.3. Integration with HTML

To support the checks in [FETCH], user agents must remember the source IP address space of contexts in which network requests are made. To this effect, the [HTML] specification is patched as follows:

  1. A new IP address space property is added to the policy container struct.

    1. It is initially public.

  2. An additional step is added to the clone a policy container algorithm:

    1. Set clone’s IP address space to policyContainer’s IP address space.

  3. An additional step is added to the create a policy container from a fetch response algorithm:

    1. Set result’s IP address space to response’s IP address space.

Assuming that example.com resolves to a public address (say, 123.123.123.123), then the Document created when navigating to https://example.com/document.html will have its policy container's IP address space property set to public.

If this Document then embeds an about:srcdoc iframe, then the child frame’s Document will have its policy container's IP address space property set to public.

If, on the other hand, example.com resolved to a loopback address (say, 127.0.0.1), then the Document created when navigating to https://example.com/document.html will have its policy container's IP address space property set to loopback.

3.4. Workers

This section is non-normative.

Given that WorkerGlobalScope already has a policy container field populated using the create a policy container from a fetch response algorithm, the avove integrations with Fetch and HTML apply just as well to worker contexts as to documents.

Assuming that example.com resolves to a public address (say, 123.123.123.123), then a WorkerGlobalScope created by fetching a script from https://example.com/worker.js will have its policy container's IP address space property set to public.

Any fetch request initiated by this worker that obtains a connection to an IP address in the local or loopback address spaces would then be a local network request.

The Service Worker soft update algorithm unfortunately sets a request client of "null" when fetching an updated script. This causes all sorts of issues, and interferes with the local network access check algorithm laid out above. Indeed, there is no request client from which to copy the policy container during fetch. [Issue #83]

4. Implementation Considerations

4.1. Where do file URLs fit?

It isn’t entirely clear how file URLs fit into the public/local scheme outlined above. It would be nice to prevent folks from harming themselves by opening a malicious HTML file locally, on the one hand, but on the other, code running locally is somewhat outside of any coherent threat model.

For the moment, let’s err on the side of treating file URLs as loopback, as they seem to be just as much a part of the loopback system as anything else on a loopback address.

Reevaluate this after implementation experience.

4.2. Proxies

In the current implementation of this specification in Chromium, proxies influence the address space of resources they proxy. Specifically, resources fetched via proxies are considered to have been fetched from the proxy’s IP address itself.

If a Document served by foo.example on a public address is fetched by the user agent via a proxy on a local address, then the Document's policy container's IP address space is set to local.

The Document will in turn be allowed to make requests to other local addresses accessible to the browser.

This can allow a website to learn that it was proxied by observing that it is allowed to make requests to local addresses, which is a privacy information leak. While this requires correctly guessing the URL of a resource on the local network, a single correct guess is sufficient.

This is expected to be relatively rare and not warrant more mitigations. After all, in the status quo all websites can make requests to all IP addresses with no restrictions whatsoever.

It would be interesting to explore a mechanism by which proxies could tell the browser "please treat this resource as public/local anyway", thereby passing on some information about the IP address behing the proxy. This might take the form of the CSP directive discussed above, with some minor modifications.

4.3. HTTP Cache

The current implementation of this specification in Chromium interacts with the HTTP cache in two noteworthy ways, depending on which kind of resource is loaded from cache.

4.3.1. Main resources

A document constructed from a cached response remembers the IP address whence the response was initially loaded. The IP address space of the document is derived anew from the IP address.

In the common case, this entails that the document's policy container's IP address space is restored unmodified. However in the event that the user agent’s configuration has changed, the derived IP address space might be different.

The user agent navigates to http://foo.example/, loads the main resource from 1.2.3.4, caches it, then sets the resulting document's policy container's IP address space to public.

The user agent then restarts, and a new configuration is applied specifying that 1.2.3.4 should be classified as a local address instead.

The user agent navigates to http://foo.example/ once more and loads the main resource from the HTTP cache. The resulting document's policy container's IP address space is now set to local.

4.3.2. Subresources

Subresources loaded from the HTTP cache are subject to the Local Network Access check. This is not yet reflected in the algoritms above, since that check is only applied in HTTP-network fetch.

Specify and explain Chromium’s behavior here. [Issue #75]

See § 5.6 HTTP cache for a discussion of security implications.

4.4. Rollout difficulties

Local Network Access essentially deprecates direct access to the local network in favor of more secure user-agent-mediated alternatives. Web deprecations are hard. Chromium has encountered many stumbling blocks on the way to shipping parts of this specification.

In particular, shipping restrictions on fetches from non-secure contexts in the local IP address space to the loopback IP address space has proven particularly difficult, for a lower payoff. Indeed, exploiting such fetches requires attackers to already have a foothold in the local network, which substantially raises attack difficulty. As a result, Chromium exempted these fetches from restrictions temporarily, choosing to focus on fetches from the public IP address space.

5. Security and Privacy Considerations

5.1. User Mediation

The proposal in this document only ensures that the device consents to access from the public internet. Users agents MAY ensure that the user consents to such access as well, as it might be in their interests to deny such access, even though the device itself would allow it.

This mediation could be done via an explicit permission grant, via some sort of pairing ceremony a la PAKE, or any other clever interface which the user agent might devise.

5.2. Mixed Content

The CORS restrictions added by the proposal in this document do not obviate mixed content checks [MIXED-CONTENT-2]. Device consent obtained through a CORS preflight request is necessary but not sufficient.

Note: [MIXED-CONTENT-2] does not prevent secure contexts from fetching resources from origins whose host is localhost or an IP address in the 127.0.0.0/8 or ::1/128 blocks. See also the definition of potentially trustworthy origins.

Developers who wish to fetch local or loopback resources (from hosts other than the above exceptions) from public pages MUST ensure that the connection is secure. This might involve a solution along the lines of [PLEX], where Web PKI certificates are issued to user-specific domain names that then resolve to local IP addresses which only make sense on the user’s local network.

Some consumer routers implement overly-aggressive protections against DNS rebinding attacks by simply blocking DNS responses that resolve to non-public IP addresses. This presents a stumbling block for solutions like [PLEX]. Workarounds are discussed in the linked issue. [Issue #23]

This problem space has been explored a few times already and seems worth revisiting at some point. One could imagine a pairing ceremony such as the one hinted at above, or one of the ideas floated in [SECURE-LOCAL-COMMUNICATION].

5.3. DNS Rebinding

The mitigation described here operates upon the IP address which the user agent actually connects to when loading a particular resource. This check MUST be performed for each new connection made, as DNS rebinding attacks may otherwise trick the user agent into revealing information it shouldn’t.

The modifications to the CORS-preflight cache are intended to mitigate this attack vector.

5.4. Scope of Mitigation

The proposal in this document merely mitigates attacks against local web services, it cannot fully solve them. For example, a router’s web-based administration interface must be designed and implemented to defend against CSRF on its own, and should not rely on a UA that behaves as specified in this document. The mitigation this document specifies is necessary given the reality of local web service implementation quality today, but vendors should not consider themselves absolved of responsibility, even if all UAs implement this mitigation.

5.5. Cross-network confusion

Most local networks cannot communicate with each other, yet they are all treated by this specification as belonging to the local IP address space. Going further, local addresses have meaning only on the local network where they are used. The same IP address might refer to entirely different devices in two different networks.

This opens the door to cross-network attacks:

None of these attacks are novel - they are just examples of the limitations of this specification.

Potential mitigations would require noticing network changes and clearing state specific to the previous network. Doing so in a fully general manner is likely to be impossible short of clearing all state. Maybe a practical compromise can be reached. [Issue #28]

5.6. HTTP cache

5.6.1. Applying checks to subresources

The following is no longer accurate. Implementation experience revealed that integrating with the cache was useful even in protecting network resources against CSRF attacks. This section needs to be rewritten. [Issue #75]

Cached subresources are not currently protected by this specification, even though the HTTP cache remembers the source IP address which could be used in the Local Network Access check algorithm during HTTP-network-or-cache fetch.

While it may be a good idea to fix this apparent discrepancy, it is not directly relevant to the main goal of this specification: preventing CSRF attacks.

At most, a malicious public website might be able to determine whether a user has visited particular local websites in the past. This attack on the user’s privacy is no worse than the status quo.

In addition, due to HTTP cache partitioning, a subresource can only be loaded from cache by malicious attackers who manage to replicate the network partition key of the cache entry. One way an attacker could achieve this is by manipulating DNS (see also § 5.3 DNS Rebinding) in order to impersonate the top-level site that initially embedded the cached resource.

The user agent navigates to http://router.example, which is served from 192.168.1.1. The website embeds a logo from http://router.example/$BRAND-logo.png, which is cached.

A malicious attacker then re-binds router.example to an attacker-controlled public IP address, and somehow tricks the user into visiting http://router.example again. The malicious website attempts to embed the logo, and monitors whether the load is successful. If so, the attacker has determined the brand of the user’s router.

5.6.2. HTTP cache poisoning

While this specification aims to protect local network servers from receiving requests from public websites, DNS rebinding can be used to carry out a similar attack through cache poisoning of unauthenticated resources.

Attackers masquerading as http://router.com can cache a malicious script at http://router.com/totally-legit.js. Later on, when the user navigates to http://router.com/, the page might request the poisoned script and execute attacker code in a less public IP address space.

This attack is partially mitigated by cache partitioning, which makes it so that the attacker must navigate a top-level browsing context to http://router.com/ before caching resources, which lacks subtlety. It is also not specific to Local Network Access, rather being a symptom of plaintext HTTP’s lack of authentication and integrity protection.

6. IANA Considerations

The Content Security Policy Directive registry should be updated with the following directives and references [RFC7762]:

treat-as-public-address

This document (see § 2.4 The treat-as-public-address Content Security Policy Directive)

7. Acknowledgements

Conversations with Ryan Sleevi, Chris Palmer, and Justin Schuh helped flesh out the contours of this proposal. Hopefully they won’t hate it too much. Mathias Karlsson has the dubious honor of being the straw that broke the camel’s back, and Brian Smith’s contributions to the resulting thread were useful, as always.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSP3]
Mike West; Antonio Sartori. Content Security Policy Level 3. URL: https://w3c.github.io/webappsec-csp/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[MINIAPP-LIFECYCLE]
Qing An; Haoyang Xu. MiniApp Lifecycle. URL: https://w3c.github.io/miniapp-lifecycle/
[RFC7762]
M. West. Initial Assignment for the Content Security Policy Directives Registry. January 2016. Informational. URL: https://www.rfc-editor.org/rfc/rfc7762
[SECURE-CONTEXTS]
Mike West. Secure Contexts. URL: https://w3c.github.io/webappsec-secure-contexts/
[SERVICE-WORKERS]
Jake Archibald; Marijn Kruisselbrink. Service Workers. URL: https://w3c.github.io/ServiceWorker/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/

Informative References

[AVASTIUM]
Avast: A web-accessible RPC endpoint can launch 'SafeZone' (also called Avastium), a Chromium fork with critical security checks removed.. URL: https://code.google.com/p/google-security-research/issues/detail?id=679
[CSRF-EXPLOIT-KIT]
Kafeine. An Exploit Kit dedicated to CSRF Pharming. URL: http://malware.dontneedcoffee.com/2015/05/an-exploit-kit-dedicated-to-csrf.html
[DRIVE-BY-PHARMING]
Sid Stamm; Zulfikar Ramzan; Markus Jakobsson. Drive-By Pharming. URL: https://link.springer.com/chapter/10.1007/978-3-540-77048-0_38
[IPV4-REGISTRY]
IANA IPv4 Special-Purpose Address Registry. URL: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
[IPV6-REGISTRY]
IANA IPv6 Special-Purpose Address Registry. URL: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
[MIXED-CONTENT-2]
Emily Stark; Mike West; Carlos Ibarra Lopez. Mixed Content Level 2. 14 October 2020. W3C First Public Working Draft. URL: https://w3c.github.io/webappsec-mixed-content/level2.html
[PLEX]
Filippo Valsorda. How Plex is doing HTTPS for all its users. URL: https://blog.filippo.io/how-plex-is-doing-https-for-all-its-users/
[RFC1122]
R. Braden, Ed.. Requirements for Internet Hosts - Communication Layers. October 1989. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc1122
[RFC1918]
Y. Rekhter; et al. Address Allocation for Private Internets. February 1996. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc1918
[RFC3927]
S. Cheshire; B. Aboba; E. Guttman. Dynamic Configuration of IPv4 Link-Local Addresses. May 2005. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc3927
[RFC4193]
R. Hinden; B. Haberman. Unique Local IPv6 Unicast Addresses. October 2005. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc4193
[RFC4291]
R. Hinden; S. Deering. IP Version 6 Addressing Architecture. February 2006. Draft Standard. URL: https://www.rfc-editor.org/rfc/rfc4291
[RFC6555]
D. Wing; A. Yourtchenko. Happy Eyeballs: Success with Dual-Stack Hosts. April 2012. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6555
[RFC6598]
J. Weil; et al. IANA-Reserved IPv4 Prefix for Shared Address Space. April 2012. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc6598
[RFC6762]
S. Cheshire; M. Krochmal. Multicast DNS. February 2013. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6762
[RFC8305]
D. Schinazi; T. Pauly. Happy Eyeballs Version 2: Better Connectivity Using Concurrency. December 2017. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8305
[SECURE-LOCAL-COMMUNICATION]
Minutes from 'Secure communication with local network devices': TPAC, 2015. URL: http://www.w3.org/2015/10/28-local-minutes.html
[SOHO-PHARMING]
Team Cymru. SOHO Pharming. URL: https://331.cybersec.fun/TeamCymruSOHOPharming.pdf
[TREND-MICRO]
TrendMicro node.js HTTP server listening on localhost can execute commands. URL: https://code.google.com/p/google-security-research/issues/detail?id=693

Issues Index

Remove the special case for IPv4-mapped IPv6 addresses once access to these addresses is blocked entirely. [Issue #36]
The definition of local network requests could be expanded to cover all cross-origin requests for which the current url's host maps to an IP address whose IP address space is not public. This would prevent a malicious server on the local network from attacking other servers. The effort require to ship such a change is not deemed worth the payoff for now. This can be shipped as an incremental improvement later on. [Issue #39]
The remote endpoint concept is not specified in [FETCH] yet, hence this is still handwaving to some extent. [Issue #33]
Preflight requests should probably be sent ahead of WebSocket handshakes, given that WebSocket handshakes have roughly the same capabilities as <img> tags. This might require no additional work to specify given that the establish a WebSocket connection depends on the Fetch algorithm. [Issue #14]
The Service Worker soft update algorithm unfortunately sets a request client of "null" when fetching an updated script. This causes all sorts of issues, and interferes with the local network access check algorithm laid out above. Indeed, there is no request client from which to copy the policy container during fetch. [Issue #83]
Reevaluate this after implementation experience.
Specify and explain Chromium’s behavior here. [Issue #75]
Some consumer routers implement overly-aggressive protections against DNS rebinding attacks by simply blocking DNS responses that resolve to non-public IP addresses. This presents a stumbling block for solutions like [PLEX]. Workarounds are discussed in the linked issue. [Issue #23]
Potential mitigations would require noticing network changes and clearing state specific to the previous network. Doing so in a fully general manner is likely to be impossible short of clearing all state. Maybe a practical compromise can be reached. [Issue #28]
The following is no longer accurate. Implementation experience revealed that integrating with the cache was useful even in protecting network resources against CSRF attacks. This section needs to be rewritten. [Issue #75]