This document is a starting point for engaging the community and standards bodies in developing collaborative solutions fit for standardization. As the solutions to problems described in this document progress along the standards-track, we will retain this document as an archive and use this section to keep the community up-to-date with the most current standards venue and content location of future work and discussions.
- This document status: Active
- Expected venue: to be determined
- Current version: this document
The motivation for BPoP closely follows the motivations for IETF DPoP, i.e. "to prevent unauthorized or illegitimate parties from using leaked or stolen access tokens, by binding a token to a public key upon issuance and requiring that the client proves possession of the corresponding private key when using the token [...]" except that, rather than binding an access token (issued by an identity provider), BPoP binds a browser artifact (such as a cookie) issued by a website.
This explainer makes direct analogs to DPoP, e.g. defining a "BPoP Proof" to match DPoP's "DPoP Proof".
The primary use case for BPoP is binding an authentication cookie. Cookies remain among the most common mechanism web servers use to store authentication state about a user. Malicious actors steal such authentication cookies and compromise user data.
A website that is its own standalone identity provider (i.e. a website that accepts a username and password) could activate BPoP as part of rending the login form. Then, on the subsequent request, when the website verifies the username and password and issues an authentication cookie, the website could also verify the BPoP proof and record the public key associated with the BPoP proof in the authentication cookie. If this website had user submitted content and such content was subsequently used as part of a stored cross site scripting (XSS) attack, this attack would be unable to steal the BPoP private key and thus the attacker would be unable to use any stolen cookies.
A website that uses a federated identity provider could activate BPoP as part of redirecting to the federated identity provider. Then, on the response back from the federated identity provider, when the website verifies the federation response and issues an authentication cookie, the website could also verify the BPoP proof and record the public key associated with the BPoP proof in the authentication cookie. If this website were vulnerable to a reflected XSS which stole the authentication cookie, the attacker would be unable to use that stolen cookie, as the attacker would be unable to produce a BPoP proof.
BPoP is also not strictly limited to cookies - it can be used to bind any artifact which is issued and accepted by the same web server (e.g. an ASP.NET ViewState).
One prominent place where authentication cookies may be shared with multiple parties is authentication cookies set in a top-level domain (example.com) but shared among sub-domains operated as distinct services. For example, an organization named Example might have distinct sub-domains support.example.com
, store.example.com
, and www.example.com
, each operated as a separate service, but capable of reading a shared authentication cookie in example.com
. By binding cookies to a public private key pair, signing over the specific origin used in the request, and limiting the authentication cookies so they can only be used with such a signature, BPoP prevents a compromised subdomain like support.example.com
from being leveraged to attack another subdomain like store.example.com
.
While it is possible for example.com
to properly audience constrain cookies today (e.g. by issuing one cookie for each subdomain, rather than one cookie in the top-level domain), doing so in practice has proven to be prohibitively cumbersome for many deployments.
A server returns a response header BPoP
to active binding. BPoP
is a structured header whose value is a dictionary. The following keys are recognized:
enabled
is a mandatory booleansubdomains
is an optional boolean whose value isfalse
if omitted.SameSite
is an optional token whose value is eitherNone
,Lax
, orStrict
and whose default isLax
if omitted.algs
is a optional string list indicating algorithms supported by the website for BPoP proofs, per RFC7518. MUST NOT include none or any identifier for a symmetric algorithm (MAC). By default, it is the list["RS256", "ES256"]
A web server may also optionally return a BPoP-Nonce
header, containing a nonce value to be included in BPoP proofs sent to them. The nonce syntax in ABNF used by RFC6749 is nonce = 1*NQCHAR
.
Thus a typical server might activate BPoP like:
BPoP: enabled
BPoP-Nonce: eyJ7S_zG.eyJH0-Z.HX4w-7v
Such a response header indicates to a browser client that it SHOULD generate a proof of possession key and attach a BPoP proof to future requests. If a browser client does not support any of the algorithms in algs
, or for any other reason, the browser may skip BPoP. If the browser skips BPoP, the web server SHOULD continue to issue cookies without binding, unless forbidden by the web server's security policy.
A BPoP proof is a signed CWT. A BPoP proof demonstrates to the server that the client holds the private key that was used to sign the BPoP proof CWT. This enables websites to bind issued browser storage artifacts (e.g cookies) to the corresponding public key and to verify the key binding of all artifacts they receive, which prevents said artifacts from being used by any entity that does not have access to the private key.
The COSE header of a BPoP CWT MUST contain at least the following parameters:
typ
with valuebpop+jwt
alg
a digital signature algorithm identifier chosen from the list indicated by the server.jwk
representing the public key chosen by the client, in JSON Web Key (JWK) format RFC7517.
The payload of a BPoP CWT MUST contain at least the following claims:
iat
creation timestamp of the CWThth
with value equal to the host value of the http request.
Following a BPoP-Nonce
header, the BPoP proof must also contain a claim nonce
with value equal to that header.
The client sends a BPoP proof on future HTTP requests.
BPoP: eyJ0eXAiOiJicG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkV
DIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1J
EQSIsImNydiI6IlAtMjU2In19.eyJodGgiOiJzZXJ2ZXIuZXhhbXBsZS5jb20iLCJp
YXQiOjE1NjIyNjI2MTZ9.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg
4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg
TODO: update this example to be a CWT instead of a JWT.
The client is expected to cache BPoP proofs and re-use them, until rejected by the server.
The client maintains a list of origins that have activated BPoP and their associated configs (subdomains
, algs
, and SameSite
). When BPoP is deactivated, e.g.:
BPoP: enabled=?0
The origin is removed from the list and the config is discarded.
If an origin that has previously configured BPoP, e.g.:
BPoP: enabled, subdomains
Reconfigures BPoP with a different configuration:
BPoP: enabled, SameSite=None
The latest configuration replaces the previous configuration. Replacement occurs for the entire config, not just for configuration elements who appear in the BPoP
header.
The browser only attaches BPoP proofs to "secure" protocols (as defined by the user agent).
The browser maintains one public private key pair per sub entity to the effective top-level domain (eTLD+1). That is, if a.example.com
, b.example.com
, and c.example.com
each activate BPoP, they share a single public private key pair.
The browser attaches BPoP proofs to a request if there exists a config that either:
- Has an exact match between the BPoP origin and the canonicalized host of the retrieval's URI and the
subdomains
flag is false - Has a domain match between the BPoP origin and the canonicalized host of the retrieval's URI and the
subdomains
flag is true
The semantics of SameSite
match the cookie attributes. That is, if the browser would not attach a cookie with SameSite=Lax to a request, and the server has initialized BPoP with SameSite=Lax, the browser should not attach a BPoP proof to the request.
A server may reject a BPoP proof because its nonce is missing or out of date:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: BPoP error="use_bpop_nonce", error_description="Web server requires nonce in BPoP proof"
BPoP-Nonce: eyJ7S_zG.eyJH0-Z.HX4w-7v
In such a case, the browser should update the BPoP proof and retry the request immediately. Servers SHALL not ask for more than one retry this way.
Such retries are intended to be seen by the client as part of a single HTTP fetch. That is, update Fetch section 4.3 HTTP Fetch with additional steps. If response is a 401 status code, and the response includes a WWW-Authentication
header indicating the BPoP
scheme with error
equal to use_bpop_nonce
and the response includes a BPoP-Nonce
header, store the nonce, regenerate the BPoP Proof, and set the actualResponse to the result of running HTTP-network-or-cache fetch for the updated fetchParams.
A server may also return a new BPoP nonce on any 200 response.
HTTP/1.1 200 Ok
BPoP-Nonce: eyJ7S_zG.eyJH0-Z.HX4w-7v
The client SHOULD start using the new nonce on the next request.
For Fetch, the client should include a BPoP proof when includeCredentials is true.
This proposal is intended to operate in the two modes already shipping in most majors browsers - a standard mode for broad audiences and an enterprise mode (equivalent to Chromium's "enterprise policy"). These modes should appear effectively the same from the perspective of a server which is unaware of enterprise features.
In standard mode:
- The browser uses one public private key pair per eTLD+1.
- The browser chooses where these keys are stored (software, hardware, roaming, etc.)
- The browser is licensed to clear these keys at any time for any reason (like cookies). The browser should avoid clearing these keys too frequently as such clears may be disruptive to the user experience (e.g. require the user to sign in again).
- The browser SHOULD clear these keys as part of any other "delete site data" experience.
If the user's machine is governed by an enterprise policy, this spec envisions that the behavior of BPoP changes as follows:
- Instead of the browser choosing keys for BPoP proofs, the enterprise policy provider chooses the keys.
- The enterprise policy provider may augment the BPoP proof payload with additional claims.
Note that neither of these changes should impact the interoperability of BPoP. As long as the web service supports the selected algorithm for the BPoP proof, the web service should be able to verify the proof and bind its cookies to that proof.
RFC 8472 defines a pattern for binding authentication tokens (including cookies) to a TLS channel. While browsers initially sent positive signals, Chromium eventually opted to remove TLS token binding in part due to the "engineering costs, maintenance costs, [...]". TLS token binding presented a number of challenges which are not present in this proposal:
- TLS token binding is not compatible with certain network stacks (e.g. HTTP3 0-RTT)
- TLS token binding is not compatible with common corporate network proxies which terminate and proxy connections to inspect traffic
- TLS token binding requires connections be kept open or resumable - not always practical over typical cookie lifetimes.
- TLS token binding deeply coupled TLS keys to authentication security, requiring integration between MDM providers and TLS stacks to satisfy enterprise management scenarios and requirements (like all keys being kept in hardware).
Instead:
- BPoP is agnostic to network stack, being an application-layer HTTP header.
- BPoP is passed through by corporate network proxies which break and inspect incoming traffic
- BPoP requires no underlying connections, functioning at the same "site data" storage layer as cookies.
- BPoP leaves the TLS layer alone. Instead, MDM providers only need to implement a narrow interface (generating a BPoP proof from their registered keys)