From af48accae9433d4b9cac9816aaeac4969f292e9a Mon Sep 17 00:00:00 2001 From: Matt Falkenhagen Date: Wed, 22 May 2019 15:24:01 +0900 Subject: [PATCH 1/2] Refinements and description of Service-Worker-Allowed. * Require Service-Worker-Allowed to be same-origin to the script URL (#1307) * Add non-normative explanation of Service-Worker-Allowed (#1405) and other mitigations. The text is highly inspired by https://infrequently.org/2014/12/psa-service-workers-are-coming/. --- docs/index.bs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/index.bs b/docs/index.bs index 269d4cf0..b7d01fb8 100644 --- a/docs/index.bs +++ b/docs/index.bs @@ -2123,6 +2123,26 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe [=/Service workers=] enable this by allowing {{Cache|Caches}} to [=/fetch=] and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the {{Cache}} as {{Response}} objects whose corresponding [=Response/responses=] are basic filtered response, the objects stored are {{Response}} objects whose corresponding [=Response/responses=] are either CORS filtered responses or opaque filtered responses. They can be passed to {{FetchEvent/respondWith(r)|event.respondWith(r)}} method in the same manner as the {{Response}} objects whose corresponding [=Response/responses=] are basic filtered responses, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing {{Cache|Caches}} to store them allows applications to avoid re-architecting in most cases. +
+

Path restriction

+ + *This section is non-normative.* + + In addition to the [[#origin-restriction|origin restriction]], service workers are restricted by the [=url/path=] of the service worker script. For example, a service worker script at https://www.example.com/~bob/sw.js can be registered for the [=scope=] https://www.example.com/~bob but not for the scope https://www.example.com or https://www.example.com/~alice. This provides some protection for sites that host multiple-user content in separated directories on the same origin. However, the path restriction is not considered a hard security boundary, as only origins are. Sites are encouraged to use different origins to securely isolate segments of the site if appropriate. + + Servers can break the path restriction by setting a [=Service-Worker-Allowed=] header on the service worker script. +
+ +
+

Service worker script request

+ + *This section is non-normative.* + + To further defend against malicious registration of a service worker on a site, this specification requires that: + * The [=Service-Worker=] header is present on service worker script requests, and + * Service worker scripts are served with a [=JavaScript MIME type=]. +
+

Implementer Concerns

@@ -2474,7 +2494,7 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Asynchronously complete these steps with a [=network error=]. 1. Let |serviceWorkerAllowed| be the result of [=extracting header list values=] given \`Service-Worker-Allowed\` and |response|'s [=response/header list=]. - Note: See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers. + Note: See the definition of the [=Service-Worker-Allowed=] header in Appendix B: Extended HTTP headers. 1. Set |httpsState| to |response|'s [=response/HTTPS state=]. 1. Set |referrerPolicy| to the result of parse a referrer policy from a Referrer-Policy header of |response|. @@ -2486,9 +2506,10 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Set |maxScopeString| to "/" concatenated with the strings, except the last string that denotes the script's file name, in |job|'s [=job/script url=]'s [=url/path=] (including empty strings), separated from each other by "/". 1. Else: 1. Let |maxScope| be the result of parsing |serviceWorkerAllowed| with |job|'s [=job/script url=]. - 1. Set |maxScopeString| to "/" concatenated with the strings in |maxScope|'s [=url/path=] (including empty strings), separated from each other by "/". + 1. If |maxScope|'s [=url/origin=] is |job|'s [=job/script url=]'s [=url/origin=]: + 1. Set |maxScopeString| to "/" concatenated with the strings in |maxScope|'s [=url/path=] (including empty strings), separated from each other by "/". 1. Let |scopeString| be "/" concatenated with the strings in |scopeURL|'s [=url/path=] (including empty strings), separated from each other by "/". - 1. If |scopeString| starts with |maxScopeString|, do nothing. + 1. If |maxScopeString| is not null and |scopeString| starts with |maxScopeString|, do nothing. 1. Else: 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. 1. Asynchronously complete these steps with a network error. From 0eadf936fcbd4afaf93ba7d8966139aea2b6cef0 Mon Sep 17 00:00:00 2001 From: Matt Falkenhagen Date: Wed, 29 May 2019 09:55:39 +0900 Subject: [PATCH 2/2] revisions --- docs/index.bs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/index.bs b/docs/index.bs index b7d01fb8..8046157c 100644 --- a/docs/index.bs +++ b/docs/index.bs @@ -2128,9 +2128,9 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe *This section is non-normative.* - In addition to the [[#origin-restriction|origin restriction]], service workers are restricted by the [=url/path=] of the service worker script. For example, a service worker script at https://www.example.com/~bob/sw.js can be registered for the [=scope=] https://www.example.com/~bob but not for the scope https://www.example.com or https://www.example.com/~alice. This provides some protection for sites that host multiple-user content in separated directories on the same origin. However, the path restriction is not considered a hard security boundary, as only origins are. Sites are encouraged to use different origins to securely isolate segments of the site if appropriate. + In addition to the [[#origin-restriction|origin restriction]], service workers are restricted by the [=url/path=] of the service worker script. For example, a service worker script at https://www.example.com/~bob/sw.js can be registered for the [=scope=] https://www.example.com/~bob/ but not for the scope https://www.example.com/ or https://www.example.com/~alice/. This provides some protection for sites that host multiple-user content in separated directories on the same origin. However, the path restriction is not considered a hard security boundary, as only origins are. Sites are encouraged to use different origins to securely isolate segments of the site if appropriate. - Servers can break the path restriction by setting a [=Service-Worker-Allowed=] header on the service worker script. + Servers can remove the path restriction by setting a [=Service-Worker-Allowed=] header on the service worker script.
@@ -2506,11 +2506,10 @@ spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-refe 1. Set |maxScopeString| to "/" concatenated with the strings, except the last string that denotes the script's file name, in |job|'s [=job/script url=]'s [=url/path=] (including empty strings), separated from each other by "/". 1. Else: 1. Let |maxScope| be the result of parsing |serviceWorkerAllowed| with |job|'s [=job/script url=]. - 1. If |maxScope|'s [=url/origin=] is |job|'s [=job/script url=]'s [=url/origin=]: + 1. If |maxScope|'s [=url/origin=] is |job|'s [=job/script url=]'s [=url/origin=], then: 1. Set |maxScopeString| to "/" concatenated with the strings in |maxScope|'s [=url/path=] (including empty strings), separated from each other by "/". 1. Let |scopeString| be "/" concatenated with the strings in |scopeURL|'s [=url/path=] (including empty strings), separated from each other by "/". - 1. If |maxScopeString| is not null and |scopeString| starts with |maxScopeString|, do nothing. - 1. Else: + 1. If |maxScopeString| is null or |scopeString| does not start with |maxScopeString|, then: 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. 1. Asynchronously complete these steps with a network error. 1. Let |url| be |request|'s [=request/url=].