Device Bound Session Credentials

Editor’s Draft,

More details about this document
This version:
https://w3c.github.io/webappsec-dbsc/
Issue Tracking:
GitHub
Editors:
(Google)
(Google)

Abstract

The Device Bound Sessions Credentials (DBSC) aims to prevent hijacking via cookie theft by building a protocol and infrastructure that allows a user agent to assert possession of a securely-stored private key. DBSC is a Web API and a protocol between user agents and servers to achieve this binding.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

Changes to this document may be tracked at https://github.com/w3c/webappsec.

The (archived) public mailing list public-webappsec@w3.org (see instructions) is preferred for discussion of this specification. When sending e-mail, please put the text “dbsc” in the subject, preferably like this: “[dbsc] …summary of comment…

This document was produced by the Web Application Security Working Group.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 03 November 2023 W3C Process Document.

1. Introduction

This section is not normative.
Note this is a very early drafting for writing collaboration only

The web is built on a stateless protocol. To provide required functionality, Web applications store data locally on a user’s computer. This is used for logged in user sessions that can last for a long time.

In general user agents do not have a secure way of storing data supporting these activities across commonly used operating systems, and actions authenticated by this data may have serious consequences, for example transferring money from a bank account.

This document defines a new API, Device Bound Sessions Credentials (DBSC), that enables the server to verify that a session cannot be exported from a device by using commonly available TPMs, or similar APIs, that are designed for this purpose.

The goal is to provide users with a safe and secure experience, while offering the use cases users are already used to. At the same time we want to ensure that the users privacy is respected with no new privacy identifiers being leaked by this protocol.

1.1. Examples

Device Bound Session Credentials are designed to make users more secure in different situations. Some of the use cases of DBSC are:

1.1.1. Signed in session

A user logs in to his social account. To protect the user’s private data the site protects his logged in session wwith a DBSC session. If the user tries to log in with the same cookie file on a different device, the site can detect and refuse this as an unauthorized user.

1.1.2. Device integrity

A commercial site has different ways of detecting unauthorized login attempts. A DBSC session on device could be used to see which users have logged on to this device before.

1.1.3. Device reputation

A payment company hosted at site payment.example.com could create a session bound to when users visit commercial site shopping.example.com. It could track the reliability of the device over time to decide how likely a transaction is legitimate.

2. Security Considerations

The goal of DBSC is to reduce session theft by offering an alternative to long-lived cookie bearer tokens, that allows session authentication that is bound to the user’s device. This makes the internet safer for users in that it is less likely their identity is abused, as malware is forced to act locally and thus becomes easier to detect and mitigate. At the same time the goal is to disrupt the cookie theft ecosystem and force it to adapt to new protections long term.

As long as the session is valid a host can know with cryptographic certainty that it is on the same device as the session was originally bound to if the session was registered to a secure device.

In order to ensure this, session private keys should be stored in a way that cannot be exfiltrated by locally running malware, whenever possible.

2.1. Non-goals

DBSC will not prevent temporary access to the browser session while the attacker is resident on the user’s device. The private key should be stored as safely as modern operating systems allow, preventing exfiltration of the session private key, but the signing capability will still be available for any program running as the user on the user’s device.

DBSC will also not prevent an attack if the attacker is replacing or injecting into the user agent at the time of session registration as the attacker can bind the session either to keys that are not TPM bound, or to a TPM that the attacker controls permanently.

DBSC is not designed to give hosts any sort of guarantee about the device a session is registered to, or the state of this device.

3. Privacy Considerations

The goal of the DBSC protocol is to introduce no additional surface for user tracking: implementing this API (for a browser) or enabling it (for a website) should not entail any significant user privacy tradeoffs.

Some of the consideration taken to ensure this:

3.1. Cookies considerations

Cross-site/cross-origin data leakage: It should be impossible for a site to use this API to circumvent the same origin policy, 3P cookie policies, etc.

Due to the complexity of current and changing cookie behavior and the interaction between DBSC and cookies the current solution is that each user agent should use the same policy for DBSC as it uses for cookies. If the DBSC cookie credential would not apply to a network request, based on user settings, applied policies or user agent implementation details, neither would any of the DBSC heuristics. This ensures no new privacy behavior due to implementing DBSC.

3.2. Timing side channel leak

If third party cookies are enabled it is possible for an attacker to leak whether or not a user is authenticated by measuring how long the request takes as the refresh is quite slow, partially due to the latency of TPM operations.

This is mitigated by requiring user opt-in through the Storage Access API. The victim site must request access to its first-party state in order for DBSC to apply within the cross-site context.

4. Alternatives considered

4.1. WebAuthn and silent mediation

5. Framework

This document uses ABNF grammar to specify syntax, as defined in [RFC5234] and updated in [RFC7405], along with the #rule extension defined in Section 7 of [RFC9112], and the quoted-string rule defined in Section 3.2.6 of the same document.

This document depends on the Infra Standard for a number of foundational concepts used in its algorithms and prose [INFRA].

5.1. Sessions by registrable domain

A sessions by registrable domain is an ordered map from registrable domain to session by id.

5.2. Sessions by id

A session by id is an ordered map from session identifier to device bound sessions for a given registrable domain.

5.3. Device bound session

A device bound session is a struct with the following items:
session identifier

a string that is a unique identifier of a session on an registrable domain

refresh url

a string that is representing the url to be used to refresh the session

defer requests

an OPTIONAL boolean defining if the browser should defer other requests while refreshing a session

cached challenge

a string that is to be used as the next challenge for this session

session scope

a struct defining which url’s' are in scope for this session

session credentials

a list of session credentials used by the session

expiration timestamp

a moment when this session should be removed.

session key

a key pair used by the session. The private key should be stored in a secure manner, see {#security-considerations}.

5.4. Session scope

The session scope is a struct with the following items:
origin

The origin this session was registered for.

include site

a boolean indicating if the session applies to an entire site or just an origin.

scope specifications

a list of scope specifications used by the session

5.5. Scope specification

The scope specification is a struct with the following items:
type

a string to be either "include" or "exclude", defining if the item defined in this struct should be added or removed from the scope

host

a string defining the domain or domain pattern that must match for this scope specification to apply.

path

a string that defines the path part of this scope specification

5.6. Session credential

The session credential is a struct with the following items:
name

a string that defines the name of the credential cookie

attributes

a string that defines the other attributes of the credential cookie

6. Algorithms

6.1. Identify session

This algorithm describes how to identify a session out of all the sessions that exist on a user agent. The session identifier is unique within a registrable domain.

Given a url and session identifier (session identifier), this algorithm returns a device bound session or null if no such session exists.

  1. Let site be the registrable domain of the url

  2. Let domain sessions be sessions by registrable domain[site] as a session by id

  3. Return domain sessions[session identifier]

6.2. Identify if a URL is in scope of a session

This algorithm describes how to determine if a URL is in scope of a device bound session. Given a url and session scope, returns true if the url is in scope, and false otherwise.
  1. If url is not same origin with the session scope origin and the origin is not the eTLD+1, return false.

  2. If the session scope origin is the eTLD+1 and the url is not same-site with the eTLD+1, return false.

  3. for each scope specification in the session scope

    1. If the host and path of url match the scope specification, return the scope specification’s type.

  4. If the url matches the session’s refresh URL, return false.

  5. If session scope sets include site, return whether url is same-site with the scope origin.

  6. Return whether url is same origin with the scope origin.

6.3. Identify session needing refresh

Given a request (request) and sessions by registrable domain, this algorithm describes how to identify which session, if any, should block request from proceeding.
  1. Let site be the registrable domain of the request’s URL.

  2. Let domain sessions be sessions by registrable domain[site] as session by id

  3. For each session of domain sessions

    1. The browser MAY skip session in order to prevent denial of service for the user or site. For example if session is requesting excessive TPM operations (harming the user) or the refresh endpoint has recently been unreachable (denial of service risk for the site).

    2. Run the steps in § 6.2 Identify if a URL is in scope of a session on the request’s URL and session’s scope.

    3. If the result does not indicate the request is in scope, skip session and continue the loop.

    4. If any of session’s credentials would be included on request, with the exception of Max-Age and Expires attributes, but are not present on request, return session.

  4. If no session has been identified, return null.

6.4. Cache challenge

This algorithm describes how to process a challenge received in an HTTP header.

Given a response (response) and a sessions by registrable domain, this algorithm updates the cached challenge for a device bound session.

  1. Let header name be "Sec-Session-Challenge".

  2. Let challenge list be the result of executing get a structured field value given header name and "list" from response’s header list.

  3. For each challenge entry of challenge list:

    1. Parse challenge entry according to parsing structured fields.

    2. If the type of challenge entry is not an sf-string, continue.

    3. Let challenge be the parsed item.

    4. Let session id be null.

    5. If params["id"] exists and is a sf-string, Set session id to params["id"].

    6. If session id is null, continue.

    7. Identify session as described in identify a session given response and session id and store as session object.

    8. If session object is null, continue.

    9. Store challenge in session object to be used next time a DBSC proof is to be sent from this device bound session.

6.5. Send request

This algorithm describes how to send a request for a device bound session registration or refresh. It takes as input an originating request, key pair, destination, and optional session id, challenge, and authorization.
  1. Let signed challenge be null. If challenge is non-null, sign it with key pair and store the result in signed challenge.

  2. Create a request for use in the HTTP-network-or-cache fetch algorithm from the Fetch specification.

  3. Set request’s method to "POST".

  4. Set request’s URL to destination.

  5. If signed challenge is non-null, add header "Sec-Session-Response" with value signed challenge to request.

  6. Set request’s initiator to originating request’s initiator.

  7. Run HTTP-network-or-Dcache fetch on request.

  8. If the result is a 401 and has a "Sec-Session-Challenge" header, start this algorithm over with a new challenge value.

  9. If the result is a redirect, and the destination does not have the HTTPS scheme and is not localhost, cancel the request.

  10. Parse the response body according to {#format-session-instructions}.

  11. If the response contains the key "continue", with value "false":

    1. Delete the session with destination’s site and identifier the value of "session_identifier".

    2. Return from this algorithm.

  12. Otherwise, perform the following validations, returning if any fail:

    1. "session_identifier" must be non-empty.

    2. "refresh_url" must be non-empty.

    3. Let origin be "scope.origin", if present, or the origin of destination if not.

    4. origin must be a valid non-opaque origin.

    5. origin must be same-site with destination.

    6. Let refresh url be the result of resolving destination with the value of "refresh_url".

    7. refresh url must have scheme HTTPS or be localhost.

    8. refresh url must be same-site with destination.

  13. If the input session id is present, delete the session with site destination’s site and identifier session id.

  14. Create a new session with:

    1. session identifier the value of "session_identifier".

    2. refresh url set to refresh url.

    3. defer requests set to true.

    4. session scope a new scope with origin origin, include site the value of "scope.include_site", and scope specifications the value of "scope.scope_specification".

    5. session credentials the value of "credentials".

    6. session key a newly-generated key pair.

6.6. Create session

To Create a new session, start with parsing the registration structured header defined in `Sec-Session-Registration`:
  1. Let header name be "Sec-Session-Registration".

  2. Let registration list be the result of executing get a structured field value given header name and "list" from response’s header list.

  3. For each registration entry, paramsregistration list:

    1. Parse registration entry according to parsing structured fields.

    2. If registration entry is not an sf-inner-list, continue.

    3. Let algorithm list be an empty list.

    4. For each algorithmregistration entry

      1. If algorithm is not a sf-token, continue.

      2. If algorithm represents a crypto algorithm supported in `Sec-Session-Registration`, and is supported on this client, add algorithm to algorithm list

    5. If algorithm list is empty, continue.

    6. If params["path"] does not exist, or is not of type sf-string, continue.

    7. Let path be params["path"].

    8. Let challenge be null, and Let authorization be null.

    9. If params["challenge"] exists and is of type sf-string Set challenge to params["challenge"].

    10. If params["authorization"] exists and is a string Set authorization to params["authorization"].

    11. Create a key pair for algorithm list.

    12. Let endpoint be the result of resolving path relative to the response’s URL.

    13. Call § 6.5 Send request with key pair, endpoint, null session id, challenge and authorization.

7. DBSC Formats

7.1. `Sec-Session-Registration` HTTP header field

The ` Sec-Session-Registration` header field can be used in a response by the server to start a new device bound session on the client.

`Sec-Session-Registration` is a List Structured Header [RFC8941]. Its ABNF is:

Sec-Session-Registration = sf-list

Each item in the list must be an inner list, and each item in the inner list MUST be a sf-token representing a supported algorithm (ES256, RS256). Only these two values are currently supported.

The following parameters are defined:

Some examples of `Sec-Session-Registration` from https://example.com/login.html:
HTTP/1.1 200 OK
Sec-Session-Registration: (ES256);path="reg";challenge="cv";authorization="ac"
HTTP/1.1 200 OK
Sec-Session-Registration: (ES256 RS256);path="reg";challenge="cv"
HTTP/1.1 200 OK
Sec-Session-Registration: (ES256);path="reg1";challenge="cv1";authorization="a"
Sec-Session-Registration: (RS256);path="reg2";challenge="cv2";authorization="b"
HTTP/1.1 200 OK
Sec-Session-Registration: (ES256);path="reg1";challenge="cv1";authorization="a", (RS256);path="reg2";challenge="cv2";authorization="b"

7.2. `Sec-Session-Challenge` HTTP Header Field

The ` Sec-Session-Challenge` header field can be used in a response by the server to send a challenge to the client that it expects to be used in future Sec-Session-Response headers inside the DBSC proof, or to request a newly signed DBSC proof right away if the status is

`Sec-Session-Challenge` is a structured header. Its value must be a string. Its ABNF is:

SecSessionChallenge = sf-string
The semantics of the item are defined in § 7.2.1 Sec-Session-Challenge structured header serialization.

The processing steps are defined in § 6.4 Cache challenge.

7.2.1. Sec-Session-Challenge structured header serialization

The `Sec-Session-Challenge` is represented as a Structured Field.[RFC8941]

In this representation, a challenge is represented by a string.

Challenges MAY have a Parameter named "id", whose value MUST be a String representing a session identifier. Any other parameters SHOULD be ignored.

Note: The server might need to use this header to request the DBSC proof to be signed with a new challenge before a session id has been assigned. In this case the session ID is optional.

Some examples of `Sec-Session-Challenge` from https://example.com/login.html:
HTTP/1.1 401 OK
Sec-Session-Challenge: "new challenge"
HTTP/1.1 401 OK
Sec-Session-Challenge: "new challenge";id="my session"
HTTP/1.1 200 OK
Sec-Session-Challenge: "new challenge";id="my session"
HTTP/1.1 200 OK
Sec-Session-Challenge: "new challenge";id="my session 1"
Sec-Session-Challenge: "another challenge";id="my session 2"
HTTP/1.1 200 OK
Sec-Session-Challenge: "c1";id="session 1", "c2";id="session 2"

7.3. Sec-Session-Response HTTP Header Field

The ` Sec-Session-Response` header field can be used in the request by the user agent to send a DBSC proof to the server to prove that the client is still in possesion of the private key of the session key.

`Sec-Session-Response` is a structured header. Its value must be a string. It’s ABNF is:

SecSessionChallenge = sf-string

This string MUST only contain the DBSC proof JWT. Any parameters SHOULD be ignored.

POST example.com/refresh
Sec-Session-Response: "eyJhbGciOiJFUzI1NiIsInR5cCI6ImRic2Mrand0In0.eyJhdWQiOiJodHRwczovL2V4YW1wbGUuY29tL3JlZyIsImp0aSI6ImN2IiwiaWF0IjoiMTcyNTU3OTA1NSIsImp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IjZfR0Iydm9RMHFyb01oNk9sREZDRlNfU0pyaVFpMVBUdnZCT2hHWjNiSEkiLCJ5IjoiSWVnT0pVTHlFN1N4SF9DZDFLQ0VSN2xXQnZHRkhRLWgweHlqelVqRUlXRSJ9LCJhdXRob3JpemF0aW9uIjoiYWMifQ.6Fb_vVBDmfNghQiBmIGe8o7tBfYPbPCywhQruP0vIhxgmcJmuNTaMHeVn_M8ZnOm1_bzIitbZqCWEn-1Qzmtyw"

7.4. Sec-Session-Id HTTP Header Field

The ` Sec-Session-Id` header field can be used in the request by the user agent to request the current session is refreshed, with the current session identifier as a string argument.

`Sec-Session-Id` is a structured header. Its value must be a string. It’s ABNF is:

SecSessionChallenge = sf-string

This string MUST only contain the session identifier. Any paramters SHOULD be ignored.

POST example.com/refresh
Sec-Session-Id: "session-id"

7.5. DBSC Session Instruction Format

The server sends session instructions during session registration and optionally during session refresh. If the response contains session instructions it MUST be in JSON format.

At the root of the JSON object the following keys can exist:

session identifier

a string representing a session identifier. If this session instructions is sent during a refresh request this MUST be the session identifier for the current session. If not these instructions SHOULD be ignored. If this session instructions is sent during a registration it MUST either be a unique iditifier for this registrable domain, or it will overwrite the current device bound session with this identifier for the current registrable domain. This key MUST be present.

refresh_url

a string representing the url used for future refresh requests. This can be a full url, or relative to the current request. This key is OPTIONAL, if not present the registration url will be used for future refresh requests.

continue

a boolean representing if the current session should continue, or be closed on the client. This key is OPTIONAL, and if not present the default value will be true.

defer_requests

a boolean describing the wanted session behavior during a session refresh. If this value is true all requests related to this session will be deferred while the session is refreshed. If instead the value is false every request will instead be sent as normal, but with a `Sec-Session-Response` header containing the DBSC proof. This key is OPTIONAL, and if not present a value of true is default.

{
  "session_identifier": "session_id",
  "refresh_url": "/RefreshEndpoint",

  "scope": {
    // Origin-scoped by default (i.e. https://example.com)
    // Specifies to include https://*.example.com except excluded subdomains.
    // This can only be true if the origin's host is the root eTLD+1.
    "origin": "example.com",
    "include_site": true,
    "continue": false,
    "defer_requests": true, // optional and true by default

    "scope_specification" : [
      { "type": "include", "domain": "trusted.example.com", "path": "/only_trusted_path" },
      { "type": "exclude", "domain": "untrusted.example.com", "path": "/" },
      { "type": "exclude", "domain": "*.example.com", "path": "/static" }
    ]
  },

  "credentials": [{
    "type": "cookie",
    // This specifies the exact cookie that this config applies to. Attributes
    // match the cookie attributes in RFC 6265bis and are parsed similarly to
    // a normal Set-Cookie line, using the same default values.
    // These SHOULD be equivalent to the Set-Cookie line accompanying this 
    // response.
    "name": "auth_cookie",
    "attributes": "Domain=example.com; Path=/; Secure; SameSite=None"
    // Attributes Max-Age, Expires and HttpOnly are ignored
  }]
}

7.6. DBSC Proof JWT Syntax

A DBSC proof proof is a JWT that is signed (using JSON Web Signature (JWS)), with a private key chosen by the client. The header of a DBSC proof MUST contain at least the following parameters:
typ

a string MUST be "dbsc+jwt"

alg

a string defining the algorithm used to sign this JWT. It MUST be either "RS256" or "ES256" from [IANA.JOSE.ALGS].

The payload of DBSC proof MUST contain at least the following claims:

aud

a string, MUST be the url this JWT was originally sent to. Example: "https://example.com/refresh.html"

jti

a string, a copy of the challenge value sent in the registration header.

iat

a string, this claim identifies the time at which the JWT was issued. This claim can be used to determine the age of the JWT. Its value MUST be a number containing a NumericDate value.

jwk

a string defining a JWK as specified in [rfc7517].

In addition the following claims MUST be present if present in `Sec-Session-Registration`:

authorization

a string, direct copy of the string from `Sec-Session-Registration`, if set there. Note that this string is OPTIONAL to include in the header, but if it is present it is MANDATORY for clients to add the claim in the DBSC proof.

An example DBSC proof sent to https://example.com/reg:
// Header
{
  "alg": "ES256",
  "typ": "dbsc+jwt"
}
// Payload
{
  "aud": "https://example.com/reg",
  "jti": "cv",
  "iat": "1725579055",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "6_GB2voQ0qroMh6OlDFCFS_SJriQi1PTvvBOhGZ3bHI",
    "y": "IegOJULyE7SxH_Cd1KCER7lWBvGFHQ-h0xyjzUjEIWE"
  },
  "authorization": "ac"
}

Based on this response header from the server:

HTTP/1.1 200 OK
Sec-Session-Registration: (ES256);path="reg";challenge="cv";authorization="ac"

recieved on a response from http://example.com/page.html

8. Changes to other specifications

8.1. Changes to the Fetch specification

This specification requires an update the HTTP-network-or-cache fetch algorithm. Between steps 10.1 and 10.2 run § 6.3 Identify session needing refresh. If the result is non-null, run § 6.5 Send request with the returned session’s key pair, refresh URL, id, cached challenge, and an empty authorization.

8.2. Changes to the Clear Site Data specification

This specification requires that the Clear Site Data specification sections 4.2.5 "Clear DOM-accessible storage for origin" clear all device bound sessions whose scope matches origin. It also requires an update to 4.2.4 to clear device bound sessions for the site matching the registered domain.

9. IANA Considerations

The permanent message header field registry should be updated with the following registrations: [RFC3864]

9.1. Sec-Session-Challenge

Header field name
Sec-Session-Challenge
Applicable protocol
http
Status
draft
Author/Change controller
W3C
Specification document
This specification (See § 7.2 `Sec-Session-Challenge` HTTP Header Field)

9.2. Sec-Session-Id

Header field name
Sec-Session-Id
Applicable protocol
http
Status
draft
Author/Change controller
W3C
Specification document
This specification (See § 7.4 Sec-Session-Id HTTP Header Field)

9.3. Sec-Session-Registration

Header field name
Sec-Session-Registration
Applicable protocol
http
Status
draft
Author/Change controller
W3C
Specification document
This specification (See § 7.1 `Sec-Session-Registration` HTTP header field)

9.4. Sec-Session-Response

Header field name
Sec-Session-Response
Applicable protocol
http
Status
draft
Author/Change controller
W3C
Specification document
This specification (See § 7.3 Sec-Session-Response HTTP Header Field)

10. Changelog

This is an early draft of the spec.

11. Acknowledgements

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

[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. URL: https://w3c.github.io/hr-time/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[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
[RFC5234]
D. Crocker, Ed.; P. Overell. Augmented BNF for Syntax Specifications: ABNF. January 2008. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc5234
[RFC7405]
P. Kyzivat. Case-Sensitive String Support in ABNF. December 2014. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc7405
[RFC8941]
M. Nottingham; P-H. Kamp. Structured Field Values for HTTP. February 2021. Proposed Standard. URL: https://httpwg.org/specs/rfc8941.html
[RFC9112]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP/1.1. June 2022. Internet Standard. URL: https://httpwg.org/specs/rfc9112.html
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/