Document Policy

Draft Community Group Report,

This version:
https://wicg.github.io/document-policy/
Issue Tracking:
GitHub
Inline In Spec
Editor:
(Google)

Abstract

This specification defines a mechanism that allows developers to ...

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 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.

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.

Should configuration points be allowed to have multiple parameters? Perhaps parameters should be defined separately, with names, types, and ranges.
When introducing a new configuration point, the default value should be chosen carefully, with highest consideration given to web compatibility. When no explicit policy has been declared for a document, the default value will be in effect.

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:

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:

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;

8.2. Integration with Fetch

The following changes should be incorporated into [FETCH]:

9. Algorithms

9.1. Is policy compatible?

Given two document policies, requiredPolicy and declaredPolicy, this algorithm returns true if declaredPolicy is compatible with requiredPolicy, or false otherwise.
  1. For each configuration pointvalue in requiredPolicy:

    1. If declaredPolicy[configuration point] does not exist, then return false.

    2. If value is stricter than declaredPolicy[configuration point], then return false.

  2. Return true.

9.2. Parse document policy

Given a dictionary (header), this algorithm returns a document policy, if it can be parsed as one, or else fails.
  1. If header is null, then return null.

  2. Let policy be a new ordered map.

  3. Let defaultEndpoint be a new string, set to null.

  4. For each name->(value,parameters) in header,

    1. Let currentEndpoint be a new string, set to null.

    2. If parameters["report-to"] exists, and is a string, then:

      1. Set currentEndpoint to the value of parameters["report-to"].

    3. If name is the string "*", then:

      1. Set defaultEndpoint to currentEndpoint.

    4. Otherwise, if name is the name of a supported configuration point, then:

      1. Let configuration point be the supported configuration point with name name.

      2. If policy[configuration point] exists, then continue with the next element.

      3. If configuration point’s type is boolean, then:

        1. If value is not a Boolean, then fail.

        2. Set policy[configuration point] to a new boolean policy configuration with value value, and reporting endpoint currentEndpoint.

        3. Continue with the next element.

      4. If configuration point’s type is enum, then:

        1. If value is not a Token, then fail.

        2. If value is not the name of one of configuration points allowed enum values, then fail.

        3. Set policy[configuration point] to a new enum policy configuration with value value, and reporting endpoint currentEndpoint.

        4. Continue with the next element.

      5. If configuration point’s type is integer, then:

        1. If value is not an Integer, then fail.

        2. If value is not in configuration point’s range, then fail.

        3. Set policy[configuration point] to a new integer policy configuration with value value, and reporting endpoint currentEndpoint.

        4. Continue with the next element.

      6. If configuration point’s type is float, then:

        1. If value is not a Decimal, then fail.

        2. If value is not in configuration point’s range, then fail.

        3. Set policy[configuration point] to a new float policy configuration with value value, and reporting endpoint currentEndpoint.

        4. Continue with the next element.

  5. For each configuration pointconfig in policy,

    1. If config does not have a reporting endpoint, set config’s reporting endpoint to defaultEndpoint.

  6. Return policy.

9.3. Serialize required policy

Given a document policy (requiredPolicy), this algorithm returns a string which represents the canonical serialization of the policy.
  1. Let dict be a new ordered map.

  2. Let features be the keys of requiredPolicy.

  3. Sort features by the name of each element, in ASCII order.

  4. For each feature in features:

    1. Let value be requiredPolicy[feature].

    2. Set dict[feature] to value.

  5. Return the serialization of dict.

9.4. Create a required policy for a browsing context

Given a browsing context (browsingContext), this algorithm returns a new Document Policy.
  1. If browsingContext is a nested browsing context, then

    1. Let requiredPolicy be a clone of browsingContext’s container document's nested context required document policy.

    2. If browsingContext’s browsing context container has a "policy" attribute, then

      1. Let containerPolicy be the result of parsing the attribute

      2. For each feature -> value in containerPolicy:

        1. If requiredPolicy[feature] does not exist, or if value is stricter than requiredPolicy[feature], then set requiredPolicy[feature] to value.

  2. Otherwise, let requiredPolicy be a new ordered map.

  3. return requiredPolicy.

9.5. Create a document Policy from response

Given a browsing context (browsingContext) and a response (response), this algorithm returns a new Document Policy.
  1. Let requiredPolicy be the result of running Create a required policy for a browsing context given browsingContext.

  2. 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.

  3. Let declaredPolicy be the result of executing Parse document policy on header.

  4. If declaredPolicy is compatible with requiredPolicy, then return declaredPolicy.

  5. Throw an exception.

9.6. Create a nested context required document policy from response

Given a browsing context (browsingContext) and a response (response), this algorithm returns a new Document Policy.
  1. Let requiredPolicy be a clone of browsingContext’s required document policy.

  2. 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.

  3. Let declaredNestedPolicy be the result of executing Parse document policy on header.

  4. For each feature -> value in declaredNestedPolicy:

    1. If requiredPolicy[feature] does not exist, or if value is stricter than requiredPolicy[feature], then set requiredPolicy[feature] to value.

  5. Return requiredPolicy.

9.7. Should response to request be blocked due to document policy?

Given a request (request) and a response (response) to that request, this algorithm returns "blocked" if the response is not compatible with the request’s required policy, or "valid" otherwise.
  1. If request has a required document policy, then

    1. 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.

    2. If documentPolicy is not compatible with request’s required document policy, return "blocked".

    3. Return "valid".

9.8. Get policy value for feature in document

Given a feature (feature) and a Document object (document), this algorithm returns the value for feature in document’s document policy.
  1. Let policy be document’s Document Policy.

  2. If policy[feature] exists, return its value.

  3. Return feature’s default value.

9.9. Determine compatibility of value with policy for feature

Given a value (value), a feature (feature) and a 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.

  1. Let policy be document’s Document Policy.

  2. Let policyConfig be policy[feature], if it exists, or a tuple consisting of feature’s default value and null, otherwise.

  3. Let policyValue and reporting endpoint be the elements of policyConfig

  4. If policyValue is stricter than value, then return a tuple consisting of "incompatible" and reporting endpoint.

  5. Let report-only policy be document’s report-only document policy,

  6. Let report-only policyConfig be report-only policy[feature], if it exists, or a tuple consisting of feature’s default value and null, otherwise.

  7. Set policyValue and reporting endpoint to the elements of report-only policyConfig

  8. If policyValue is stricter than value, then return a tuple consisting of "compatible" and reporting endpoint.

  9. Return ("compatible", null).

9.10. Determine if value is compatible with policy for feature or report

Given a value (value), a feature (feature) and a 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.
  1. Let (action, reporting endpoint) be the result of calling determine-compatibility with value, feature and document.

  2. If reporting endpoint is not null,

    1. 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".

    2. 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.

    3. Let settings be document’s environment settings object.

    4. Execute Reporting API § 2.3 Queue data as type for destination with body, "document-policy-violation", reporting endpoint and settings.

  3. Return action.

9.11. Determine if value is compatible with policy for feature

Given a value (value), a feature (feature) and a Document object (document), this algorithm returns "compatible" if value is compatible with document’s document policy, or else "incompatible".
  1. Let (action, reporting endpoint) be the result of calling determine-compatibility with value, feature and document.

  2. 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.

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.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[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/
[REPORTING]
Douglas Creager; et al. Reporting API. 25 September 2018. WD. URL: https://www.w3.org/TR/reporting-1/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC3864]
G. Klyne; M. Nottingham; J. Mogul. Registration Procedures for Message Header Fields. September 2004. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc3864

Informative References

[CSP]
Mike West. Content Security Policy Level 3. 29 June 2021. WD. URL: https://www.w3.org/TR/CSP3/
[ECMA-262]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[PERMISSIONS-POLICY]
Ian Clelland. Permissions Policy. 16 July 2020. WD. URL: https://www.w3.org/TR/permissions-policy-1/

Issues Index

Should configuration points be allowed to have multiple parameters? Perhaps parameters should be defined separately, with names, types, and ranges.