From 9b71920c8e8c63271caed5f47d84c3318fabfa2f Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 17 Jul 2019 22:37:29 +0200 Subject: [PATCH 01/13] Add data pod definition. --- main/introduction.bs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/introduction.bs b/main/introduction.bs index 6515545a..0b9546c1 100644 --- a/main/introduction.bs +++ b/main/introduction.bs @@ -12,4 +12,5 @@ Issue: Explain that this specification is not documentation; ## Definitions ## {#definitions} -Issue: Write Definitions section. +A data pod is a place for storing documents, +with mechanisms for controlling who can access what. From ef51c0be41d598fdbf14458feb4a10361ff1db23 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 17 Jul 2019 22:37:37 +0200 Subject: [PATCH 02/13] Add Solid app definition. --- main/introduction.bs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/main/introduction.bs b/main/introduction.bs index 0b9546c1..14eab817 100644 --- a/main/introduction.bs +++ b/main/introduction.bs @@ -14,3 +14,6 @@ Issue: Explain that this specification is not documentation; A data pod is a place for storing documents, with mechanisms for controlling who can access what. + +A Solid app is an application +that reads or writes data from one or more [=data pods=]. From 546b5d58a26ce84364770afcde7bdffbd2e6ce5b Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 17 Jul 2019 23:12:52 +0200 Subject: [PATCH 03/13] Add CORS background and need. --- main/index.bs | 1 + main/resource-access.bs | 46 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/main/index.bs b/main/index.bs index f49c8b19..e1990b29 100644 --- a/main/index.bs +++ b/main/index.bs @@ -5,6 +5,7 @@ Level: 1 Status: w3c/ED Group: Solid Community Group URL: https://solid.github.io/specification/ +Markup Shorthands: markdown yes Max ToC Depth: 2 Editor: Your Name, Your Company http://example.com/your-company, your-email@example.com, http://example.com/your-personal-website Abstract: diff --git a/main/resource-access.bs b/main/resource-access.bs index 4d72d8af..51c0bb43 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -41,6 +41,52 @@ A Solid data pod MUST conform to the Web Access Control specification [[!WAC]]. ## Cross-Origin Resource Sharing ## {#cors} +### Background and Need ### {#cors-need} +This section is non-normative. + +[=Solid apps=] typically access data from multiple sources. +However, +Web browsers by default prevent apps that run on one origin +from accessing data on other origins. +This cross-origin protection is a security mechanism +that ensures malicious websites cannot simply read +your profile or banking details from other websites. +However, this reasonable default poses a problem +even for benevolent Solid apps, +which might have good reasons to access data from different places. +For instance, +a Solid app at `https://app.example/` +would be prevented from accessing data on +`https://alice-data-pod.example/` or `https://bob-data-pod.example/`, +even when Alice and Bob have given the user of the app +their permission to see some of their data. + +For cases where the other origins +have their own access protection mechanism— +[like within Solid](#wac)— +the browser's built-in cross-origin protection +is actually an obstacle rather than a feature. +After all, +[=data pods=] already ensure through access control +that certain documents can only be accessed by specific people. +Preventively blocking apps from different origins +thus introduces an unnecessary barrier. + +Fortunately, +Web servers can indicate to the browser +that certain documents do not require cross-origin protection. +This mechanism to selectively disable that protection +is called *Cross-Origin Resource Sharing* or *CORS* [[FETCH]]. +By responding to browser requests +with a specific combination of HTTP headers, +servers can indicate which actions are allowed for a given resource. +For a Solid data pod, +the goal is to allow *all* actions on the CORS level, +such that the deeper [access control layer](#wac) +can exert full control over the app's allowed permissions. +The next section describes how to achieve this +through the right HTTP header configuration. + Issue: Write Cross-Origin Resource Sharing section. A Solid data pod MUST conform to the CORS specification [[!FETCH]]. From 889de3f373e7930bf94297df181a6ac161212147 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 18 Jul 2019 23:07:34 +0200 Subject: [PATCH 04/13] Explain initial CORS requirements. --- main/resource-access.bs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/main/resource-access.bs b/main/resource-access.bs index 51c0bb43..46fd4909 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -87,6 +87,22 @@ can exert full control over the app's allowed permissions. The next section describes how to achieve this through the right HTTP header configuration. -Issue: Write Cross-Origin Resource Sharing section. - -A Solid data pod MUST conform to the CORS specification [[!FETCH]]. +### Required server-side implementation ### {#cors-server} + +A [=data pod=] MUST implement the CORS protocol [[!FETCH]] +such that no request to it or response from it +is blocked by the browser. +If the data pod wishes to block access to a resource, +this MUST NOT happen via CORS +but MUST instead be communicated to the Solid app in the browser +through HTTP status codes such as `401`, `403`, or `404` [[!RFC7231]]. +Furthermore, +all response headers MUST be exposed to the Solid app. + +Note: Since the CORS protocol is part of a Living Standard, +it should still be considered in evolution. +Changes to the CORS protocol might thus happen at any point, +which might necessitate changes to server implementations +to prevent undesired blocking. +A [proposal](https://github.com/whatwg/fetch/issues/878) to mitigate this +has been suggested. From f9f297d2be4a882e515980c5f94ad0237216dc19 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Thu, 18 Jul 2019 23:42:34 +0200 Subject: [PATCH 05/13] Discuss concrete CORS implementation. --- main/resource-access.bs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/main/resource-access.bs b/main/resource-access.bs index 46fd4909..b2d45395 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -90,8 +90,8 @@ through the right HTTP header configuration. ### Required server-side implementation ### {#cors-server} A [=data pod=] MUST implement the CORS protocol [[!FETCH]] -such that no request to it or response from it -is blocked by the browser. +such that, to the extent possible, +no request to it or response from it is blocked by the browser. If the data pod wishes to block access to a resource, this MUST NOT happen via CORS but MUST instead be communicated to the Solid app in the browser @@ -103,6 +103,32 @@ Note: Since the CORS protocol is part of a Living Standard, it should still be considered in evolution. Changes to the CORS protocol might thus happen at any point, which might necessitate changes to server implementations -to prevent undesired blocking. +for continued prevention of undesired blocking. A [proposal](https://github.com/whatwg/fetch/issues/878) to mitigate this has been suggested. + +Concretely, +whenever a data pod receives an HTTP request +containing an `Origin` header [[!RFC6454]], +the server MUST respond with the appropriate `Access-Control-*` headers +as specified in the CORS protocol [[!FETCH]]. +A data pod MUST also support the HTTP `OPTIONS` method [[!RFC7231]] +such that it can respond appropriately to CORS preflight requests. + +Careful attention is warranted, +especially because of the many edge cases. +For instance, +data pods SHOULD enumerate all response headers under `Access-Control-Expose-Headers` +because there are cases (credentials mode set to `include`) +where using `*` as a value does not work. +As another example, +data pods SHOULD always explicitly list `Accept` under `Access-Control-Allow-Headers`. +This is recommended because, +despite `Accept` being safelisted, +values longer than 128 characters are blocked by default, +and the number of available RDF formats that Solid apps might use +could easily lead to longer value lengths. + +Note: Under the current CORS protocol, +the correct HTTP response headers depend on the specifics of the request +and thus cannot be pre-generated. From 183b7c5a15883aeafe0f5552830477f4bee8c2d8 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Fri, 19 Jul 2019 00:13:50 +0200 Subject: [PATCH 06/13] Add security considerations from CORS. --- main/security.bs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/main/security.bs b/main/security.bs index 870a9f85..b1910019 100644 --- a/main/security.bs +++ b/main/security.bs @@ -3,6 +3,33 @@ Security Considerations {#security} Issue: Write Security Considerations section. +Solid data pods [disable all cross-origin protections](#cors-server) in browsers +because resource access is governed explicitly by [Web Access Control](#wac). +As such, +data pods MUST NOT rely on cross-origin protection +for shielding access to resources. +While this ensures that unauthorized resource access will not occur, +additional security measures MAY be needed +to prevent metadata in error responses from leaking. +For instance, +a malicious app could probe multiple servers +to check whether the response status code is `401` or `403`, +or could try to access an error page +from an intranet server within the user agent's private network +to extract company names or other data. +To mitigate this, +when a request from an untrusted the `Origin` arrives, +the data pod MAY set the status code of error responses to `404` +and/or anonymize or censor their contents. + +A data pod MUST NOT assume that the user agent is a regular Web browser, +even when requests contain familiar values +in headers such as `User-Agent` or `Origin`. + + ## Privacy Considerations ## {#privacy} Issue: Write Privacy Considerations section. + +In order to prevent leakage of non-resource data, +error responses SHOULD NOT contain identifiable information. From 6077959bd500ab3775d76b9cb92691fb4a57897f Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Fri, 19 Jul 2019 15:35:40 +0200 Subject: [PATCH 07/13] Review after feedback by @pmcb55 and @csarven. --- main/resource-access.bs | 23 +++++++++++++++-------- main/security.bs | 28 ++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/main/resource-access.bs b/main/resource-access.bs index b2d45395..d4dadfbf 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -87,15 +87,20 @@ can exert full control over the app's allowed permissions. The next section describes how to achieve this through the right HTTP header configuration. + ### Required server-side implementation ### {#cors-server} A [=data pod=] MUST implement the CORS protocol [[!FETCH]] such that, to the extent possible, -no request to it or response from it is blocked by the browser. +the browser does not block +any request sent to it or response received from it. If the data pod wishes to block access to a resource, this MUST NOT happen via CORS but MUST instead be communicated to the Solid app in the browser -through HTTP status codes such as `401`, `403`, or `404` [[!RFC7231]]. +through HTTP status codes such as +`401 Unauthorized`, +`403 Forbidden`, +or `404 Not Found` [[!RFC7231]]. Furthermore, all response headers MUST be exposed to the Solid app. @@ -124,11 +129,13 @@ where using `*` as a value does not work. As another example, data pods SHOULD always explicitly list `Accept` under `Access-Control-Allow-Headers`. This is recommended because, -despite `Accept` being safelisted, -values longer than 128 characters are blocked by default, -and the number of available RDF formats that Solid apps might use -could easily lead to longer value lengths. +while CORS allows some headers such as `Accept` by default, +they are blocked when their value exceeds 128 characters +(which is not uncommon for RDF consumers such as Solid apps). -Note: Under the current CORS protocol, -the correct HTTP response headers depend on the specifics of the request +Note: +The correct HTTP response headers depend on the specifics of the request and thus cannot be pre-generated. +For example, +`Access-Control-Allow-Origin: *` cannot be used with a credentials mode of `include` +and should instead reflect a valid `Origin` sent by the client. diff --git a/main/security.bs b/main/security.bs index 680f309c..eed67f3c 100644 --- a/main/security.bs +++ b/main/security.bs @@ -3,29 +3,41 @@ Security Considerations {#security} Issue: Write Security Considerations section. +A data pod MUST NOT assume that HTTP request headers +sent by a client are valid. +For example, +values for `Host` and `Origin` +MUST NOT be assumed to be free of possibly malicious sequences +such as `/..` or others. + +A data pod MUST NOT assume that the user agent is a regular Web browser, +even when requests contain familiar values +in headers such as `User-Agent` or `Origin`. +Such an assumption could incorrectly lead to conclusions +about the security model of the application making the request, +whereas the request might actually come +from a malicious actor that is not bound to the same security constraints. + Solid data pods [disable all cross-origin protections](#cors-server) in browsers because resource access is governed explicitly by [Web Access Control](#wac). As such, data pods MUST NOT rely on cross-origin protection for shielding access to resources. While this ensures that unauthorized resource access will not occur, -additional security measures MAY be needed +additional security measures MAY be taken to prevent metadata in error responses from leaking. For instance, a malicious app could probe multiple servers -to check whether the response status code is `401` or `403`, +to check whether the response status code is +`401 Unauthorized` or `403 Forbidden`, or could try to access an error page from an intranet server within the user agent's private network to extract company names or other data. To mitigate this, -when a request from an untrusted the `Origin` arrives, -the data pod MAY set the status code of error responses to `404` +when a request from an untrusted `Origin` arrives, +the data pod MAY set the status code of error responses to `404 Not Found` and/or anonymize or censor their contents. -A data pod MUST NOT assume that the user agent is a regular Web browser, -even when requests contain familiar values -in headers such as `User-Agent` or `Origin`. - ## Privacy Considerations ## {#privacy} From 0b7df5c25a390dc88825d7499b36a27e43509459 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 30 Jul 2019 19:17:31 +0200 Subject: [PATCH 08/13] Remove status texts, as they are non-binding. See https://github.com/solid/specification/pull/13#discussion_r308779850 --- main/resource-access.bs | 4 +--- main/security.bs | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/main/resource-access.bs b/main/resource-access.bs index 3076cc02..5ccd6065 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -127,9 +127,7 @@ If the data pod wishes to block access to a resource, this MUST NOT happen via CORS but MUST instead be communicated to the Solid app in the browser through HTTP status codes such as -`401 Unauthorized`, -`403 Forbidden`, -or `404 Not Found` [[!RFC7231]]. +`401`, `403`, or `404` [[!RFC7231]]. Furthermore, all response headers MUST be exposed to the Solid app. diff --git a/main/security.bs b/main/security.bs index eed67f3c..ec638c5a 100644 --- a/main/security.bs +++ b/main/security.bs @@ -28,14 +28,13 @@ additional security measures MAY be taken to prevent metadata in error responses from leaking. For instance, a malicious app could probe multiple servers -to check whether the response status code is -`401 Unauthorized` or `403 Forbidden`, +to check whether the response status code is `401` or `403`, or could try to access an error page from an intranet server within the user agent's private network to extract company names or other data. To mitigate this, when a request from an untrusted `Origin` arrives, -the data pod MAY set the status code of error responses to `404 Not Found` +the data pod MAY set the status code of error responses to `404` and/or anonymize or censor their contents. From cd7af5b14aad16e5504bd3964a96f442d5995aa5 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Fri, 2 Aug 2019 11:42:33 +0200 Subject: [PATCH 09/13] Review after feedback by @csarven. --- main/resource-access.bs | 43 +++++++++++++++++++++-------------------- main/security.bs | 19 ++++++++++-------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/main/resource-access.bs b/main/resource-access.bs index 5ccd6065..ea077ca9 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -121,15 +121,16 @@ through the right HTTP header configuration. A [=data pod=] MUST implement the CORS protocol [[!FETCH]] such that, to the extent possible, -the browser does not block -any request sent to it or response received from it. +the browser allows Solid apps +to send any request and combination of request headers +to the data pod, +and the Solid app can read any response and response headers +received from the data pod. If the data pod wishes to block access to a resource, this MUST NOT happen via CORS but MUST instead be communicated to the Solid app in the browser through HTTP status codes such as `401`, `403`, or `404` [[!RFC7231]]. -Furthermore, -all response headers MUST be exposed to the Solid app. Note: Since the CORS protocol is part of a Living Standard, it should still be considered in evolution. @@ -141,28 +142,28 @@ has been suggested. Concretely, whenever a data pod receives an HTTP request -containing an `Origin` header [[!RFC6454]], +containing a valid `Origin` header [[!RFC6454]], the server MUST respond with the appropriate `Access-Control-*` headers as specified in the CORS protocol [[!FETCH]]. +In particular, +the data pod MUST set the `Access-Control-Allow-Origin` header +to the valid `Origin` value from the request +and list `Origin` in the `Vary` header value. +The data pod MUST make all used response headers readable for the Solid app +through `Access-Control-Expose-Headers` +(with the possible exception of the `Access-Control-*` headers themselves). A data pod MUST also support the HTTP `OPTIONS` method [[!RFC7231]] such that it can respond appropriately to CORS preflight requests. Careful attention is warranted, especially because of the many edge cases. For instance, -data pods SHOULD enumerate all response headers under `Access-Control-Expose-Headers` -because there are cases (credentials mode set to `include`) -where using `*` as a value does not work. -As another example, -data pods SHOULD always explicitly list `Accept` under `Access-Control-Allow-Headers`. -This is recommended because, -while CORS allows some headers such as `Accept` by default, -they are blocked when their value exceeds 128 characters -(which is not uncommon for RDF consumers such as Solid apps). - -Note: -The correct HTTP response headers depend on the specifics of the request -and thus cannot be pre-generated. -For example, -`Access-Control-Allow-Origin: *` cannot be used with a credentials mode of `include` -and should instead reflect a valid `Origin` sent by the client. +data pods SHOULD explicitly enumerate +all used response headers under `Access-Control-Expose-Headers` +rather than resorting to `*`, +which does not cover all cases (such as credentials mode set to `include`). +Data pods SHOULD also explicitly list `Accept` under `Access-Control-Allow-Headers`, +because values longer than 128 characters +(not uncommon for RDF-based Solid apps) +would otherwise be blocked, +despite shorter `Accept` headers being allowed without explicit mention. diff --git a/main/security.bs b/main/security.bs index ec638c5a..fcbc05bd 100644 --- a/main/security.bs +++ b/main/security.bs @@ -1,22 +1,25 @@ Security Considerations {#security} =================================== -Issue: Write Security Considerations section. - -A data pod MUST NOT assume that HTTP request headers -sent by a client are valid. +A data pod MUST NOT assume that +HTTP request headers sent by a client are valid, +and MUST reject or sanitize invalid header values +before processing them +or incorporating them in messages sent to others. For example, values for `Host` and `Origin` MUST NOT be assumed to be free of possibly malicious sequences -such as `/..` or others. +such as `/..` or others, +and invalid `Origin` values +MUST NOT be echoed into the `Access-Control-Allow-Origin` response header. A data pod MUST NOT assume that the user agent is a regular Web browser, even when requests contain familiar values in headers such as `User-Agent` or `Origin`. -Such an assumption could incorrectly lead to conclusions +Such an assumption could lead to incorrect conclusions about the security model of the application making the request, -whereas the request might actually come -from a malicious actor that is not bound to the same security constraints. +since the request might actually come +from a non-browser actor unaffected by browser security constraints. Solid data pods [disable all cross-origin protections](#cors-server) in browsers because resource access is governed explicitly by [Web Access Control](#wac). From 44ec98b3b940e284e98246a3a65b9e06d28fb03d Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Sun, 4 Aug 2019 21:54:19 +0200 Subject: [PATCH 10/13] Review after feedback by @justinwb. --- main/resource-access.bs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/resource-access.bs b/main/resource-access.bs index ea077ca9..4b6c44ea 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -97,7 +97,8 @@ the browser's built-in cross-origin protection is actually an obstacle rather than a feature. After all, [=data pods=] already ensure through access control -that certain documents can only be accessed by specific people. +that certain documents can only be accessed +by specific people or applications. Preventively blocking apps from different origins thus introduces an unnecessary barrier. From 3912ad14aefac4a761160dcd74f612c40c97a1fd Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 6 Aug 2019 12:22:07 +0200 Subject: [PATCH 11/13] Add security consideration on Living Standards. --- main/security.bs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main/security.bs b/main/security.bs index fcbc05bd..e36b2627 100644 --- a/main/security.bs +++ b/main/security.bs @@ -1,6 +1,12 @@ Security Considerations {#security} =================================== +Some of the normative references with this specification +point to documents with a _Living Standard_ status, +meaning their contents can still change over time. +It is advised to monitor these documents, +as such changes might have security implications. + A data pod MUST NOT assume that HTTP request headers sent by a client are valid, and MUST reject or sanitize invalid header values From 0f4d5dc9aa3086394370e7ba0ca79770c576a3bd Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Tue, 6 Aug 2019 16:05:11 +0200 Subject: [PATCH 12/13] Disallow cookies from untrusted origins. --- main/security.bs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/main/security.bs b/main/security.bs index e36b2627..72aa52e4 100644 --- a/main/security.bs +++ b/main/security.bs @@ -30,10 +30,11 @@ from a non-browser actor unaffected by browser security constraints. Solid data pods [disable all cross-origin protections](#cors-server) in browsers because resource access is governed explicitly by [Web Access Control](#wac). As such, -data pods MUST NOT rely on cross-origin protection -for shielding access to resources. -While this ensures that unauthorized resource access will not occur, -additional security measures MAY be taken +data pods MUST NOT rely on browser-based cross-origin protection mechanisms +for determining the authentication status or representation of a resource. +In particular, +they MUST ignore HTTP cookies from untrusted origins. +Additional security measures MAY be taken to prevent metadata in error responses from leaking. For instance, a malicious app could probe multiple servers From 6957bddbe77b9d3194ebf877d5a6841cab831323 Mon Sep 17 00:00:00 2001 From: Ruben Verborgh Date: Wed, 7 Aug 2019 16:16:06 +0200 Subject: [PATCH 13/13] Review after feedback by @TallTed. --- main/resource-access.bs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/main/resource-access.bs b/main/resource-access.bs index 4b6c44ea..bc3ab822 100644 --- a/main/resource-access.bs +++ b/main/resource-access.bs @@ -134,9 +134,8 @@ through HTTP status codes such as `401`, `403`, or `404` [[!RFC7231]]. Note: Since the CORS protocol is part of a Living Standard, -it should still be considered in evolution. -Changes to the CORS protocol might thus happen at any point, -which might necessitate changes to server implementations +it might be changed at any point, +which might necessitate changes to data pod implementations for continued prevention of undesired blocking. A [proposal](https://github.com/whatwg/fetch/issues/878) to mitigate this has been suggested.