1. Introduction
This document defines Document Policy, which is a framework for designing configurable features as part of the web platform, and for allowing web developers to configure those features as part of their site deployment.
2. Examples #
Needs new examples. For now, see explainer.
3. Other and related mechanisms
Document Policy is similar in scope to some existing mechanisms for document configuration, though there are significant differences from each.
3.1. Relation to Permissions Policy
Permissions Policy [PERMISSIONS-POLICY] is another mechanism which allows authors to configure features in documents, and is similar in scope, though it use a different inheritance mechanism, which makes it more suitable for certain types of features, separate from those which are suitable for control by Document Policy.
Historically, Document Policy was created as a response to a number of proposed feature additions to Permissions Policy (named Feature Policy at the time), which either didn’t quite fit the existing 'feature' model, or required significant additional complexity to be added to the Permissions Policy spec. This included features with parameters, features with optional inheritance into subframes, and features which would inherit differently in popups than in other top-level browsing contexts.
Those features are now proposed to be covered by Document Policy, and Permissions Policy is used for features where delegation is the primary concern. Permissions Policy features are boolean-valued (either enabled or disabled), can never be re-enabled in a child frame if disabled in its parent, and generally follow the model of "available in top-level browsing contexts and their same-origin children; must be delegated to cross-origin frames."
In contrast, features controlled by Document Policy may take parameters, and those parameters may have unrelated values in different frames (constraining a feature in a parent frame does not necessarily constrain its child frames.)
3.2. Relation to Content Security Policy
Content-Security-Policy [CSP] also configures 'features' in documents, although it is primarily concerned with the origin of resources in a page, rather than controlling what those resources can do once loaded.
CSP also provides a different mechanism for setting sandbox flags on a document, through the sandbox directive. If sandbox flags are moved to document policy, then this may be redundant, as the two headers may encode identical information.
CSP-Embedded-Enforcement introduced a model for forcing a policy to be adhered to by child documents, and for rejecting non-conforming documents as network errors during Fetch. This model is adopted by document policy for the required policy mechanism.
3.3. Relation to Sandboxing
Iframe sandboxing is another mechanism for controlling features in documents, and behaves in a very similar manner to document policy’s required policies: disabling a feature is something that can be imposed on a frame, and affects all content loaded into that frame.
The features which are controlled by the iframe sandbox attribute could be expressed very naturally with document policy.
One key difference between iframe sandboxing and document policy is that all sandbox features are applied by default when the 'sandbox' attribute is used on a frame, and must be re-enabled one-by-one. This makes it very difficult to extend the sandboxing model with new features, as any additions will immediately affect all existing sandboxed content. Additionally, there is no mechanism for the origin server to know that its content will be sandboxed, so it is difficult to add new sandbox features which could potentially alter control flow in a sandboxed document, as this could introduce new security vulnerabilities in existing content.
4. Framework
4.1. Configuration Points
A configuration point is a Web Platform API or behavior which can be enabled, diabled, or configured through Document Policy. Configuration points should be defined in the specification which describes the underlying API or behavior, although there is a registry of defined configuration points in use attached to this document.
A configuration point has a name, which is a token.
A configuration point has a type, which is one of:
-
boolean
, -
integer
, -
float
, or -
enum
.
A configuration point has a range, which is a subset of all values for its type.
A configuration point has a default value, which is an element of its range.
4.2. Policies
A document policy is an ordered map from configuration points to policy configurations
A policy configuration is a tuple consisting of a value, which is an element of the configuration point’s range, and a reporting endpoint, which is a string, and which may be null.
A browsing context has a required document policy, which is a document policy. A browsing context with a null opener browsing context has an empty required document policy.
A Document has a nested context required document policy, which is a document policy.
A Document has a document policy, which is a document policy.
A Document has a report-only document policy, which is a document policy.
5. Required Policy Serialization
-
Explain here how required policies are serialized as structured headers.
-
Ensure that there is a canonical form (for compat testing).
6. Reporting
A site deploying a document policy may want to know if any of the policies
which are set on its pages are violated. For instance, a site which sets a
policy requiring all images to be match the size of their containers may want
to be alerted if a new developer or CMS inserts oversized images into content.
Similarly, a site which deploys a policy which restricts the use of the document.write
API may want to receive reports if a script is ever imported
which uses it.
This section defines a mechanism for reporting such violations using the Reporting API. [REPORTING]
A site may also want to test out a policy in real-world situations before enforcing it. This section also defines a "Report-only" mode, where the user agent can watch for situations which would be policy violations and report on them, without enforcing the policy. This allows site owners to work to drive the real-world violation count down to an acceptable level before actually deploying the policy.
Reporting is only possible from the page which configures the policy. It is not possible to receive reports from a nested page which violates a required policy.
"Violation" is defined per-feature, but should always reflect an action of the web developer, rather than the user directly.
This implies that not all policies can be reported on. There is a class of feature whose settings cannot be said to be "violated" in any meaningful way by markup, or by script actions. A hypothetical feature which disabled text entry in form fields, for instance, could be enforced by the user agent, but if a user were to try to type in those fields, causing enforcement to be required, that would not represent a violation of the policy, and should not be reported.
6.1. Configuring in-document reporting
6.1.1. The "report-to" parameter
Any directive can include a parameter named report-to
, which names a
reporting endpoint to which violation reports for that feature will
be sent.
Example:
Document-Policy: something=1.0;report-to=endpoint1, something-else=?0;report-to=endpoint2
6.1.2. Setting the default reporting endpoint
If violations for many or all features should be sent to the same endpoint,
then it may be easier to define a single default endpoint. This can
be defined by a parameter on the special token *
. If a default endpoint is provided, then unless otherwise specified, all violation
reports will be sent to that named endpoint. If a feature also specifies its
own endpoint, with the report-to
parameter, then reports will go to that
endpoint instead. (Reports are not sent to both endpoints.)
Example:
Document-Policy: something=1.0, something-else=?0, *;report-to=endpoint
6.1.3. Disabling reporting for a feature
If a default endpoint has been specified, then it may be necessary to
disable reporting for specific features. This can be done by specifying the
special endpoint name none
as the value for the report-to
parameter.
This will override the default endpoint and disable reporting for that
feature.
Example:
Document-Policy: something=1.0;report-to=none, something-else=?0, *;report-to=endpoiont
6.2. Report-only mode
A document policy can be a "report-only" policy. Report-only policies are
specified with a Document-Policy-Report-Only
header. Violations of a
report-only policy will cause a report to be generated, as the enforcing
policy would, but they do not cause any other action to be taken by the user
agent.
Document-Policy-Report-Only
The report-to
directive parameter should be used with directives in this
header, or else they will have no effect at all.
Example:
Document-Policy-Report-Only: something=1.0;report-to=endpoint, something-else=?0;report-to=endpoint2
7. Delivery
7.1. Policies as Structured Headers
Policies are represented in HTTP headers and in HTML attributes as the serialization of an sh-dictionary structure. Each dictionary member is a document policy directive.
A document policy directive is an element of a serialized document policy, and consists of a directive name, which is an sh-token, and associated parameters.
A directive name may be one of:
-
The name of a configuration point
-
The Token "
*
".
A policy value is an element of the range for the named configuration point.
7.1.1. Parameters
Any document policy directive may include a parameter named report-to
, whose value must be a string.
A document policy directive whose directive name names a configuration point with type boolean
has no required parameters.
A document policy directive whose directive name names a configuration point with type integer
has a required parameter, whose value must be an
integer in the configuration point’s range.
A document policy directive whose directive name names a Configuration point with type float
has a required parameter, whose value must be a decimal
in the configuration point’s range.
A document policy directive whose directive name names a configuration point with type enum
has a required parameter, whose value must be 'true',
and whose name must be a token in the configuration point’s range.
Examples:
-
boolean-feature
-
boolean-feature=?0
-
integer-feature=2
-
float-feature=-0.2
-
enum-feature=state
7.2. HTTP Headers
7.2.1. Document-Policy
The `Document-Policy
` HTTP
header can be used in the response (server to client) to communicate the document policy that should be enforced by the client.
The Document-Policy
header is a Structured Header. Its value
must be a dictionary. Its ABNF is:
Document-Policy = sh-dictionary
If any dictionary member name does not name a supported configuration point or the special value "*", then the dictionary memver will be ignored by the processing steps.
7.2.2. Document-Policy-Report-Only
The `Document-Policy-Report-Only
`
HTTP header can be used in the response (server to client) to configure
the report-only document policy for the document.
The Document-Policy-Report-Only
header is a Structured Header.
Its value must be a dictionary. It has exactly the same syntax as the Document-Policy
header.
7.2.3. Require-Document-Policy
The `Require-Document-Policy
`
HTTP header field is a response header which is used to communicate to the
client the minimum required document policy to apply to all nested
content.
The Require-Document-Policy
header is a Structured Header dictionary, with
exactly the same syntax as the Document-Policy
header.
7.2.4. Sec-Required-Document-Policy
The `Sec-Required-Document-Policy
`
HTTP header field is a request header which is used to communicate to the
server the document policy which must be sent with the document
returned with the request.
The header’s value is the § 5 Required Policy Serialization of one or more document policy directives
7.3. The policy
attribute of the iframe
element
iframe
elements have a "policy
" attribute, which contains a required
policy directive (SH format).
8. Integrations
If a frame has a required policy, then that policy must be advertised in the request header for any outgoing document requests, to inform the server of the policy which will be applied to the document by the user agent. This allows the server to alter the representation which is returned, to conform to that policy.
In the case where a required policy request header is present, the response must contain a compatible document policy header, or the fetch will fail.
8.1. Integration with HTML
The following changes should be incorporated into [HTML]:
-
iframe
elements should have the following IDL added:
[CEReactions] attribute DOMString policy;
-
The iframe policy attribute should be defined as follows:
-
The
policy
attribute, when specified, adds a required document policy to theiframe
's nested browsing context, when it is initialized. Its value must be a serialized document policy.
-
-
In HTML § 3.1.1 The Document object, add the following lines:
-
The Document has a document policy, which is a document policy, which is initially empty.
-
The Document has a nested context required document policy, which is a document policy, which is initially empty.
-
-
In the creating a new browsing context algorithm:
-
Add the following step after step 5:
-
Set browsingContext’s required document policy to the result of creating a required policy for a browsing context browsingContext.
-
-
Change step 9 (renumbered now to 10) to read:
-
Let document be a new Document, marked as an HTML document in quirks mode, whose content type is
"text/html"
, origin is origin, active sandboxing flag set is sandboxFlags, permissions policy is permissions policy, document policy is identical to browsingContext’s required document policy, and which is both ready for post-load tasks and completely loaded immediately.
-
-
-
In the process a navigate fetch algorithm:
-
Add the following step after step 5:
-
Set request’s required document policy to browsingContext’s required document policy.
-
-
-
In the initialise the document object algorithm:
-
Add the following steps after step 3:
-
Let documentPolicy be the result of creating a document policy for browsingContext from response.
-
Let nestedContextRequiredDocumentPolicy be the result of creating a nested context document policy for browsingContext from response.
-
-
Change step 6 (renumbered now to 8) to read:
-
Let document be a new Document, whose type is type, content type is contentType, origin is origin, permissions policy is permissionsPolicy, active sandboxing flag set is finalSandboxFlags, document policy is documentPolicy, and nested context required document policy is nestedContextRequiredDocumentPolicy.
-
-
8.2. Integration with Fetch
The following changes should be incorporated into [FETCH]:
-
In Fetch Standard § 2.2.5 Requests, add the following:
-
A request has an associated required document policy, which is a document policy. Unless otherwise stated, it is null.
-
-
In Fetch Standard § 4.6 HTTP-network-or-cache fetch, after step 15, insert the following:
-
If httpRequest has a required document policy, then
-
Let serializedRequiredPolicy be the result of calling Serialize Required Policy on httpRequest’s required document policy.
-
Append
Sec-Required-Document-Policy
/serializedRequiredPolicy to httpRequest’s header list.
-
-
-
In Fetch Standard § 4.1 Main fetch, add the following algorithm to the list of algorithms in step 11:
9. Algorithms
9.1. Is policy compatible?
-
For each configuration point → value in requiredPolicy:
-
If declaredPolicy[configuration point] does not exist, then return false.
-
If value is stricter than declaredPolicy[configuration point], then return false.
-
-
Return true.
9.2. Parse document policy
-
If header is null, then return null.
-
Let policy be a new ordered map.
-
Let defaultEndpoint be a new string, set to null.
-
For each name->(value,parameters) in header,
-
Let currentEndpoint be a new string, set to null.
-
If parameters["report-to"] exists, and is a string, then:
-
Set currentEndpoint to the value of parameters["report-to"].
-
-
If name is the string "
*
", then:-
Set defaultEndpoint to currentEndpoint.
-
-
Otherwise, if name is the name of a supported configuration point, then:
-
Let configuration point be the supported configuration point with name name.
-
If policy[configuration point] exists, then continue with the next element.
-
If configuration point’s type is boolean, then:
-
If value is not a Boolean, then fail.
-
Set policy[configuration point] to a new boolean policy configuration with value value, and reporting endpoint currentEndpoint.
-
Continue with the next element.
-
-
If configuration point’s type is enum, then:
-
If value is not a Token, then fail.
-
If value is not the name of one of configuration points allowed enum values, then fail.
-
Set policy[configuration point] to a new enum policy configuration with value value, and reporting endpoint currentEndpoint.
-
Continue with the next element.
-
-
If configuration point’s type is integer, then:
-
If value is not an Integer, then fail.
-
If value is not in configuration point’s range, then fail.
-
Set policy[configuration point] to a new integer policy configuration with value value, and reporting endpoint currentEndpoint.
-
Continue with the next element.
-
-
If configuration point’s type is float, then:
-
If value is not a Decimal, then fail.
-
If value is not in configuration point’s range, then fail.
-
Set policy[configuration point] to a new float policy configuration with value value, and reporting endpoint currentEndpoint.
-
Continue with the next element.
-
-
-
-
For each configuration point → config in policy,
-
If config does not have a reporting endpoint, set config’s reporting endpoint to defaultEndpoint.
-
-
Return policy.
9.3. Serialize required policy
-
Let dict be a new ordered map.
-
Let features be the keys of requiredPolicy.
-
Sort features by the name of each element, in ASCII order.
-
For each feature in features:
-
Let value be requiredPolicy[feature].
-
Set dict[feature] to value.
-
-
Return the serialization of dict.
9.4. Create a required policy for a browsing context
-
If browsingContext is a nested browsing context, then
-
Let requiredPolicy be a clone of browsingContext’s container document's nested context required document policy.
-
If browsingContext’s browsing context container has a "policy" attribute, then
-
Let containerPolicy be the result of parsing the attribute
-
For each feature -> value in containerPolicy:
-
If requiredPolicy[feature] does not exist, or if value is stricter than requiredPolicy[feature], then set requiredPolicy[feature] to value.
-
-
-
-
Otherwise, let requiredPolicy be a new ordered map.
-
return requiredPolicy.
9.5. Create a document Policy from response
-
Let requiredPolicy be the result of running Create a required policy for a browsing context given browsingContext.
-
Let header be the result of calling get a structured field value with header name
Document-Policy
and type "dictionary
" from response’s header list. -
Let declaredPolicy be the result of executing Parse document policy on header.
-
If declaredPolicy is compatible with requiredPolicy, then return declaredPolicy.
-
Throw an exception.
9.6. Create a nested context required document policy from response
-
Let requiredPolicy be a clone of browsingContext’s required document policy.
-
Let header be the result of calling get a structured field value with header name
Required-Document-Policy
and type "dictionary
" from response’s header list. -
Let declaredNestedPolicy be the result of executing Parse document policy on header.
-
For each feature -> value in declaredNestedPolicy:
-
If requiredPolicy[feature] does not exist, or if value is stricter than requiredPolicy[feature], then set requiredPolicy[feature] to value.
-
-
Return requiredPolicy.
9.7. Should response to request be blocked due to document policy?
-
If request has a required document policy, then
-
Let documentPolicy be the result of calling get a structured field value with header name
Document-Policy
and type "dictionary
" from response’s header list. -
If documentPolicy is not compatible with request’s required document policy, return "blocked".
-
Return "valid".
-
9.8. Get policy value for feature in document
Document
object (document), this
algorithm returns the value for feature in document’s document
policy.
-
Let policy be document’s Document Policy.
-
If policy[feature] exists, return its value.
-
Return feature’s default value.
9.9. Determine compatibility of value with policy for feature
Document
object
(document), this algorithm returns a tuple consisting of:
-
An action, which is either "compatible" or "incompatible", depending on whether value is compatible with document’s document policy,
-
A reporting endpoint name, which will be null if value is compatible with both document’s document policy and its report-only document policy, or if reporting is not configured for feature, or else will be the name of the reporting endpoint to which a violation report should be sent.
Note that if the enforcing policy is stricter than the report-only policy, then the report-only policy will not be checked.
-
Let policy be document’s Document Policy.
-
Let policyConfig be policy[feature], if it exists, or a tuple consisting of feature’s default value and null, otherwise.
-
Let policyValue and reporting endpoint be the elements of policyConfig
-
If policyValue is stricter than value, then return a tuple consisting of "incompatible" and reporting endpoint.
-
Let report-only policy be document’s report-only document policy,
-
Let report-only policyConfig be report-only policy[feature], if it exists, or a tuple consisting of feature’s default value and null, otherwise.
-
Set policyValue and reporting endpoint to the elements of report-only policyConfig
-
If policyValue is stricter than value, then return a tuple consisting of "compatible" and reporting endpoint.
-
Return ("compatible", null).
9.10. Determine if value is compatible with policy for feature or report
Document
object
(document), this algorithm returns "compatible" if value is compatible
with document’s document policy, or else "incompatible". It will
also queue a report if reporting has been configured.
-
Let (action, reporting endpoint) be the result of calling determine-compatibility with value, feature and document.
-
If reporting endpoint is not null,
-
Let body be a new ECMAScript object with the following properties: [ECMA-262]
- featureId
-
feature’s string representation.
- sourceFile
-
null
- lineNumber
-
null
- columnNumber
-
null
- disposition
-
"enforce", if action is "incompatible", or else "report".
-
If the user agent is currently executing script, and can extract the source file’s URL, line number, and column number from settings, then set body’s sourceFile, lineNumber, and columnNumber accordingly.
-
Let settings be document’s environment settings object.
-
Execute Reporting API § 2.3 Queue data as type for destination with body, "document-policy-violation", reporting endpoint and settings.
-
-
Return action.
9.11. Determine if value is compatible with policy for feature
Document
object
(document), this algorithm returns "compatible" if value is compatible
with document’s document policy, or else "incompatible".
-
Let (action, reporting endpoint) be the result of calling determine-compatibility with value, feature and document.
-
Return action.
10. IANA Considerations
The permanent message header field registry should be updated with the following registrations [RFC3864]:
- Header field name
- Document-Policy
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- Document Policy API
- Header field name
- Require-Document-Policy
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- Document Policy API
- Header field name
- Sec-Required-Document-Policy
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- Document Policy API
11. Privacy and Security
This specification standardizes a mechanism for an embedding page to set a
policy which will be enforced on an embedded page. Explicit acknowledgment of
a required policy is required, however, unlike existing the existing iframe sandbox
, mechanism. This means that behaviors of existing features
cannot be changed in published web sites, without the cooperation of those
sites.
There are some privacy and security considerations to keep in mind with this model:
-
Exposure of behavior in a cross-origin subframe to its embedder.
-
Exposure of embedder state to the embedded document thorough policy.
-
Unanticipated behavior change by blindly accepting a required policy.
To a degree, these concerns are already present in the web platform, and this specification attempts to at least not make them needlessly worse.
Security and privacy issues may also be caused by the design of individual configuration points, so care must be taken when integrating with this specification. This section attempts to provide some guidance as to what kinds of behaviors could cause such issues.
11.1. Exposure of cross-origin behavior
Configuraton points should be designed such that a violation of the policy in a framed document is not observable by documents in other frames. For instance, a hypothetical feature which caused a event to be fired in the embedding document if it is used while disabled by policy, could be used to extract information about the state of an embedded document. If the feature is known only to be used while a user is logged in to the site, for instance, then the embedder could disable that feature for the frame, and then listen for the resulting events to determine whether or not the user is logged in.
Additionally, care must be taken so that information about the contents of cross-origin resources (which is not normally available to a document) is not made visible by a policy. Image contents, for instance, may contain private information, and a fine-grained policy may allow an attacker to infer something about the contents of the image by carefully tuning the policy’s configuration parameter. Policies which act on the contents of subresources should either exclude non-readable resources, or take steps to limit the amount of information which can be inferred about the resource.
11.2. Advertisement of required policy
As a mitigation to the behavior change problem discussed above, requests for embedded content in a frame with a required policy will be sent with an HTTP header detailing the policy requirements. This header is visible to origin servers, and its contents may reveal details about the embedder page. Embedders should be aware of this when choosing to require a policy on their embedded content.
11.3. Blind acceptance of required policy
Since adhering to the embedder-required policy is necessary in order to be
loaded, site owners may be tempted to configure web servers to simply echo the Sec-Required-Document-Policy
request header in the response’s Document-Policy
header. While this will ensure that the document’s policy is
always compatible with the request, it may open up the embedded document to
the risk that the embedder can alter control flow within it, by disabling or
changing the behavior of existing APIs. This is especially true as new
configuration points are added to the document policy model after the content
is written. It is difficult to future-proof a document against all possible
new behavior changes.
Sites which expect to be embedded in a context with a required document policy can mitigate this by setting their policy to the actual strictest policy that they know they can support, or by echoing the incoming policy for only the configuration points which they are aware of, and understand the potential scope of behavior changes.