Delegated Account Recovery draft-hill-delegated-recovery
Delegated Account Recovery allows an application to delegate the capability to recover an account (e.g. in the event of a credential loss or compromise) to an account controlled by the same user or entity at a third party service provider.
This Unofficial Draft will expire on April 29, 2018.
Copyright (c) 2016-2017 Facebook, Inc. and the persons identified as the document authors and published under the Creative Commons Attribution 4.0 International license.
In this document, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in BCP 14, RFC 2119 [RFC2119].
This document deals with the formatting of tokens in an external representation using a casually defined syntax drawing from that used in [RFC5246] and resembling the programming language "C". The purpose is to document the binary token format only.
The basic numeric data type is an unsigned byte (uint8). All larger numeric data types are formed from fixed-length series of bytes concatenated from left to right and are also unsigned. The following numeric types are predefined.
uint8 uint16[2]; uint8 uint32[4]; uint8 uint64[8];
All values, here and elsewhere in the specification, are stored in network byte (big-endian) order; the uint32 represented by the hex bytes 01 02 03 04 is equivalent to the decimal value 16909060.
The type string is defined as a concatenated sequence of octet sequences representing ASCII characters, one per octet. [RFC3629]
The term URL is defined by reference to [RFC3986] in this document. "URL" is used deliberately in preference to "URI" as all such objects in this document are used to access network resources and such objects as used by this document lack any persistent meaning after the resource to which they refer ceases to exist.
Network services that rely on user credentials must also cope with the reality that users may forget or lose exclusive control of these credentials. As a consequence, nearly every such service must implement an alternate authentication process to enable a user to recover control of an account. In practice, there are few good options for doing this, and these recovery flows are often the weakest link in securing accounts.
A common and self-contained method of account recovery is to ask the user additional questions that they are less likely to forget the answer to than a more arbitrary password. The same features that make such a question useful for recovery also reduce its security:
Password hints are extremely problematic - by definition they must be revealed to an unauthenticated user, which implies reversibly encrypted storage at best, reveals information about a password (or often the password itself), and common hints at multiple services may reveal where a password is reused, facilitating further attacks.
Users are unlikely to forget their email address, and a common practice is to email the user URL that encodes the ability to recover the account. This is the most widely deployed mechanism at the time of this writing, but it has a number of shortcomings.
Federated systems for authentication take many forms and solve the problem of account recovery (or at least delegate it implicitly to the Identity Provider). However, after fifteen years of widespread deployment of such systems, we see few mainstream services that are willing to rely exclusively on federated logins for a variety of reasons.
Methods do exist to strongly re-authenticate an account holder in the absence of a password or other primary credential. Device-based or multi-factor authentication, multi-device authentication, or trusted connections in a social network are possibilities. Unfortunately, of the potentially hundreds of services a user interacts with in a year, only a few are likely able to leverage such factors. The rest will lack the information, resources, and user consent needed. Furthermore, the characteristics that make good recovery systems strong also may make them unique to a particular service, preventing broad adoption as a best practice by other providers.
Delegated Recovery is similar in some respects to OAuth [RFC5849]and related protocols.
It is not constructed simply as a profile of one these protocols as it relies on different trust semantics. Because tokens granting an account recovery capability are expected to have an indefinite lifetime and should be able to remain valid even following the compromise and/or rotation of the keys they were originally issued under, tokens in this protocol derive their authority at a point in time from being signed with currently published public keys, discoverable over HTTPS.
As this trust model is different than other protocols in the broad OAuth family, profiling an existing protocol to fit these needs would likely be considerably more complex than implementing a new, minimalist protocol from scratch. As such, the latter approach has been taken here.
Goals for Delegated Account Recovery include:
Delegated Recovery defines three roles:
+--------+ +------+ +----+---+ |Account | | User | |Recovery| |Provider| | | |Provider| | | | | | | +-+------+ +--+---+ +----+---+ | | | | 1. Select Recovery | | | Provider | | |<--------------------+ | | | 2. Retrieve | | | Configuration | +---------------------------------------->| |<----------------------------------------+ | | | +----+ 3. Generate Recovery| | | | Token | | +--->| | | | | | | 4. Redirect User | | | Agent to Recovery | | | Provider with Token | | +-------------------->+------------------>| | | | | | 5. (if needed) | | | Authenticate User | | |<------------------+ | +------------------>| | | | | | 6. Retrieve | | | Configuration | |<----------------------------------------+ +---------------------------------------->| | | | | (optional) | 7. Verify and +---+ | 8. Notify Account | Save Recovery | | | Provider with | Token |<--+ | Result Code for | | | token ID | | |<----------------------------------------+ | | | | 9. Redirect User | | | Agent back to | | | Account Provider | | | | | |<--------------------+<------------------+ | | | | | | V V V
Figure 1: Recovery Capability Establishment
The abstract Delegated Recovery capability establishment flow illustrated in Figure 1 describes the interaction between the three roles and includes the following steps:
+--------+ +------+ +----+---+ |Account | | User | |Recovery| |Provider| | | |Provider| | | | | | | +-+------+ +--+---+ +----+---+ | (optional) | | | 1. Initiate Recovery| | | | | |<--------------------+ | | | | | | (optional) | | | 2. Retrieve | | | Configuration | +---------------------------------------->| |<----------------------------------------+ | | | | (optional) | | | 3. Offer User link | 1. Initiate | | to Recovery Provider| Recovery | | with origin hint | | +-------------------->+------------------>| | | | | | 4. (if needed) | | | Authenticate User | | |<------------------+ | +------------------>| | | | | | 5. Retrieve | | | Configuration | |<----------------------------------------+ +---------------------------------------->| | | | | | 6. Retrieve and +---+ | 7. Send User | Counter-Sign | | | Agent to Account | Recovery Token |<--+ | Provider with | | | Counter-Signed | | | Recovery Token | | |<--------------------+<------------------+ | | | | | 8. Retrieve | | | Configuration | +---------------------------------------->| |<----------------------------------------+ | | | +----+ 9. Validate | | | | Recovery Token | | +--->| | | | | | | | | | 10. Restore Control | | | of Account | | |-------------------->| | | | | V V V
Figure 2: Exercising a Recovery Capability
The abstract flow depicting the exercising of a Delegated Recovery capability in Figure 2 describes the interaction between the the roles and includes the following steps:
Whenever Transport Layer Security (TLS) is used by this specification, the appropriate version (or versions) of TLS will vary over time, based on the widespread deployment and known security vulnerabilities. At the time of this writing, TLS version 1.2 [RFC5246]is the most recent and widely deployed version.
Implementations may also support additional transport-layer security mechanisms that meet their security requirements.
This specification makes extensive use of HTTP redirections, in which the client or the authorization server directs the resource owner's user-agent to another destination. While the examples in this specification show the use of the HTTP 302 status code, any other method available via the user-agent to accomplish this redirection is allowed and is considered to be an implementation detail.
When retrieving configuration servers SHOULD NOT follow redirects to reduce the risk of Server Side Request Forgery.
This specification is written primarily for a general purpose web browser as user agent but this is not the only possible implementation choice. On some platforms, some of either or both of the Account Provider and Recovery Provider functionality may be provided as part of a dedicated, platform-native application, AKA an "app". Generally, as the protocol aims to coordinate between authenticated sessions at multiple service providers, the platform standard web browser is the most standardized and convenient mechanism available and should be preferred.
Fetching Configuration is the process of determining the protocol endpoints and public keys used by Account Providers and Recovery Providers.
Service providers may indicate that configuration responses are cacheable and may cache responses but cache lifetimes should be kept reasonably short to enable timely responses to events such as key compromise.
Fetching configuration begins by normalizing the service provider to be used into an RFC6454[RFC6454] ASCII serialization of an Origin with an https scheme.
Retrieval of the configuration is done using an HTTP GET request to the provider's configuration endpoint at the following absolute path relative to the https:// Origin. /.well-known/delegated-account-recovery/configuration
The configuration resource path on the http:// scheme MUST NOT redirect to the https:// protocol, as this may mask configuration mistakes by consumers. Servers MUST return an empty response body and an HTTP status code in the 400 range (401 is recommended) if /.well-known/delegated-account-recovery/configuration is accessed with the http:// scheme
When fetching configuration, service providers MUST NOT follow redirects that do not use an https:// scheme. Service providers generally should avoid utilizing redirects when returning configuration responses. As it is not mandatory that the issuer field or endpoints in a configuration agree with the origin of the configuration URL, directly returning the canonical data rather than a redirect reduces latency in the protocol.
A Recovery Provider MUST return the following information in a JSON dictionary comprising the entire response body:
* NOTE: A Recovery Provider may also impose per-account limitations on the total storage or number of recovery tokens it allows. The token-max-size property only sets an upper bound on the length of a single token, and it may still reject tokens below this bound for reasons not discoverable in public configuration.
An Account Provider MUST return the following information in a JSON dictionary comprising the entire response body:
An origin that acts as both an Account and a Recovery provider MUST return a single JSON dictionary as the entire response body containing all required keys.
URLs [RFC3986]MUST have a scheme component that is https, a host component, and optionally, port and path components, and no query or fragment components. Note that no relationship can be assumed between the host component of the issuer input and those of of the URLs in the configuration. (e.g. "https://www.messenger.com" might have account recovery endpoints at "https://www.facebook.com")
Each phase (establishing, and exercising, an account recovery capability) utilizes three protocol endpoints. (HTTP resources)
All protocol endpoints MUST use the https:// scheme, and the protocol endpoint paths at the http:// scheme MUST NOT redirect to the https:// protocol, as this may mask configuration mistakes by clients. A GET or POST to protocol endpoint paths using the http:// scheme MUST yield an empty response body and an HTTP status code 401.
When establishing a recovery capability, the following endpoints are used:
When exercising a recovery capability, the following endpoints are used:
Additionally, an Account Provider may optionally provide a "Token Status" endpoint at a well-known location to allow the Recovery Provider to provide direct status updates for tokens, such as the success or failure of saving a token, token deletion, or repudiation of the exercise of a recovery capability.
save-token is used to interact with the Recovery Provider and save a recovery token for later use. The Recovery Provider MUST first authenticate the User. The way in which the Recovery Provider authenticates the User is beyond the scope of this specification.
Save Token endpoints which expect to receive invocations by web user agents MUST support the HTTP "POST" method and SHOULD reject the HTTP "GET" method.
If navigating from an Account Provider implemented as a native app to a general purpose web browser and POST is not available, the Account Provider SHOULD first navigate the user agent to a resource under its control and use that resource to perform the POST.
The POST body MUST be application/x-www-form-urlencoded formatted. It MUST contain a parameter token containing the recovery token.
The POST body MAY contain the additional parameter 'login_hint'. This value may be set to indicate the Account Provider's notion of the primary contact point for the user. A Recovery Provider might match this against the currently logged in user to determine what UI treatments, if any, to apply to confirm saving of the recovery token.
The POST body MAY contain the additional parameter 'login_hint_sha256'. This value may be set to indicate the Account Provider's notion of the primary contact point for the user. A Recovery Provider might match this against the currently logged in user to determine what UI treatments, if any, to apply to confirm saving of the recovery token. The value should contain the base64 encoded concatenation of a 256 bit random salt value with the binary output of the SHA-256 hashing algorithm applied to the concatenation of the salt and an octet string representing the ASCII serialization of the primary contact point hint for the user at the Account Provider. Use of 'login_hint_sha256', when compared to 'login_hint', allows matching without disclosure, but introduces the possibility that legitimate matches will not be discovered due to differences in how contact point hints are represented or canonicalized before hashing.
The POST body MAY contain an additional parameter 'nickname_hint' to suggest a nickname for the account to which the token relates.
The POST body MAY contain an additional parameter 'confirmation'. If set to the value 'required', this indicates to the Recovery Provider that it SHOULD show some form of interstitial explicitly informing the user that a token will be saved, with the option to decline.
The POST body type MAY contain an additional parameter, 'obsoletes'. The value of the 'obsoletes' is a token id which the current token is intended to replace. If the user at the Recovery Provider has a saved token with an id and issuer matching this property, it should be deleted or marked as invalid if the new token is successfully saved.
The POST body MAY contain an additional parameter 'state', the value of which will be passed to the 'save-token-return' endpoint, unmodified.
When a user wishes to save a recovery token, the Account Provider takes the following processing steps:
Upon receiving an invocation of the Save Token endpoint the Recovery Provider takes the following processing steps:
Save Token Return is used to return the User to the Account Provider after invoking Save Token at the Recovery Provider.
Save Token Return endpoints MUST support both the HTTP GET and POST methods.
Upon receiving an invocation of the Save Token Return endpoint the Recovery Provider may use the "status" parameter to report whether a token was successfully saved, regardless of whether asynchronous status updates for the token were requested. The 'state' parameter may be used, if needed, to determine the next action to be taken.
In order to facilitate greater control over the user experience for an Account Provider, or to expose advanced features, a Recovery Provider may optionally provide as part of its configuration a save-token-async-api-iframe URL.
This URL may be used as the src attribute of an <iframe> tag in an HTML document. When loaded, the resource MUST expose an API based on HTML cross-document messaging. (https://html.spec.whatwg.org/multipage/comms.html#web-messaging)
The details of how such a resource communicates with services at the Recovery Provider are not normatively specified by this document.
The normative API exposed is as follows:
The message argument to postMessage() MUST be a JSON object.
Messages related to this API MUST always contain the property 'delegated-account-recovery-api-message' with a value indicating the type of the protocol message.
The following message types are defined by their literal string values:
For messages that elicit a response, the Account Provider may set an 'id' property on the message. If present, the Recovery Provider MUST include its value as the value of the property 'in-reply-to' in the correlated response.
The Account Provider SHOULD set the targetOrigin parameter to the origin of the URL obtained from the Recovery Provider configuration, to reduce the risk that messages will be visibile to unintended recpiients.
On loading, the async API resource MUST post a message to its parent of type 'ready'.
This message type MUST have an additional property, 'token', that contains the base64 encoded recovery token to be saved.
This message type MAY contain the additional property 'login_hint'. These values may be set to indicate the Account Provider's notion of the primary contact points for the user. A Recovery Provider might match these against the currently logged in user to determine what UI treatments, if any, to apply to confirm saving of the recovery token.
This message type MAY contain an additional property 'nickname_hint' to suggest a nickname for the account to which the token relates.
This message type MAY contain an additional property 'state' which will be passed, unmodified, as part of the redirect to the 'save-token-return' endpoint.
This message type MAY contain an additional property, 'obsoletes'. The value of the 'obsoletes' property is a token id which the current token is intended to replace. If the user at the Recovery Provider has a saved token with an id and issuer matching this property, it should be deleted or marked as invalid if the new token is successfully saved.
If no other keys are set on the message, the behavior of the Recovery Provider iframe will be to process the message and navigate the parent frame based on the results of that processing.
If the Recovery Provider needs to perform additional interactions with the user to complete saving the token, (such as login, confirmation of the save or collecting a token nickname) it can redirect the parent window to whatever location is necessary to complete the flow interactively at the Recovery Provider. It SHOULD always attempt to return the user to the Account Provider's save-token-return endpoint at the end of these flows, with the provided 'state' parameter, whether successful or not.
If the recovery token can be saved without user interaction, the iframe SHOULD navigate the parent frame directly to the Account Provider's save-token-return endpoint with the status parameter set to 'save-success' and any 'state' parameter set.
This message has identical arguments to the 'save-token' message.
It is processed identically, except it MUST NOT navigate the parent frame. Instead, results are conveyed by it issuing a postMessage() to its parent window with a message of type 'save-token-result' and a 'result' property.
This method may be preferred by a caller that wants to guarantee the user isn't navigated away from a critical experience they are interacting with, like an account creation funnel. The account provider might choose to, e.g. open a popup with a POST directly to the 'save-token' endpoint to complete any interaction with the Recovery Provider if the value of 'result' is not 'save-success'.
The value of the 'state' property on the message, if set, is ignored.
It is processed identically, except that instead of navigating the parent frame, it issues a postMessage() to its parent window immediately after the message is accepted, with a message type of 'save-token-result' and a 'result' property. The only valid value for the 'result' key in response to a 'save-token-async-only' message is 'done'. No indication is provided of the success or failure of the operation.
How a message is determined to be accepted is an implementation detail at the discretion of the Recovery Provider. It might reject messages locally (e.g. if it does not support silent acceptance for this Account Provider or the user), it might dispatch them immediately using an API like Beacon, if available, or it may need to make an asynchronous HTTP request and wait for a response. It SHOULD indicate "done" to the caller at the earliest practical moment.
This protocol message would typically be employed with a token that sets the 'status-requested' flag and by an Account Provider that keeps track of what recovery tokens have been recorded for an account. It might be used to optimistically enroll users in recovery as part of another action, with an offer to complete the flow interactively at a later time made to users not successfully enrolled asynchronously.
This message is sent to the parent frame in response to a 'save-token-no-navigation' or 'save-token-async-only' message.
This message contains a 'result' property. If sent in response to a 'save-token-no-navigation' message, the value of result will be either 'save-token-success' or 'save-token-failure', indicating whether the token was saved without user interaction. If sent in response to a 'save-token-async-only' message, the value is always 'done', indicating when it is safe to navigate or otherwise destroy the iframe hosting the API.
This message indicates a request for a token binding string from the Recovery Provider. The reply contains a string that should be treated as opaque by the receiver and placed into the 'binding' field of a recovery token.
Bindings are optional according to this specification but individual Recovery Providers MAY, at their discretion, require a token contain a valid binding to be saved.
Bindings SHOULD be considered to be unique and single-use and the string received in response to a call to 'get-binding' SHOULD NOT be associated to more than one token.
This message has no arguments other than the optional 'id' for reply correlation.
This message replies to a 'get-binding' message.
The API MUST provide a response to such a message. An empty string is a valid binding string.
The property 'binding' of this message contains the binding string.
A recipient of this message SHOULD treat it as unique and single-use, but the API implementation MAY return the same binding string for multiple invocations at the same instance of the iframe resource.
Recovery Providers are not required to process all APIs uniformly. For example, a Recovery Provider might refuse to process 'save-token-async-only' messages from certain issuers, or only attempt to process them if the Account Provider is the canonical owner of the users's primary contact point at the Recovery Provider. (e.g. a Recovery Provider might silently accept a recovery token from https://example.com only if it's own view of the authenticated user had a confirmed email address at example.com)
Implementers should take caution that the binding message does not leak information about a user. It SHOULD NOT provide the same or a correlatable response across different instances of the iframe resource implementing the API, and SHOULD NOT provide bindings that are distinguishable by callers based on user state or properties. (logged in, user identifier, user IP address, etc)
The Recover Account endpoint is used to exercise a saved recovery capability.
A user may arrive at the Recover Account Endpoint in at least two ways:
Recover Account endpoints MUST support both the HTTP GET and POST methods.
A query string or application/x-www-form-urlencoded formatted POST body MAY be provided. If a query string is provided, it MAY contain the parameter issuer set to the origin of the Account Provider and/or a id parameter set to the hex value of a token_id. These parameters can be used by the Recovery Provider to guide the user in selecting the correct token. For example, if used as part of a cryptographic key recovery ceremony, it may be necessary to select a specific token among several the user has saved from a given issuer.
Upon receiving an invocation of the Recover Account endpoint the Recovery Provider takes the following processing steps:
The Recover Account Return endpoint is used to return the User to the Account Provider after invoking Recover Account at the Recovery Provider.
Recover Account Return endpoints MUST support the HTTP POST and SHOULD reject the HTTP GET method.
If navigating from a Recovery Provider implemented as a native app to a general purpose web browser and POST is not available, the Recovery Provider SHOULD first navigate the user agent to a resource under its control and use that resource to perform the POST.
The POST body MUST be application/x-www-form-urlencoded formatted. It must contain the query parameter countersigned-token containing the countersigned recovery token.
Upon receiving an invocation of the Recover Account Return endpoint the Account Provider takes the following processing steps:
The Token Status endpoint is used by the Recovery Provider to notify the Account Provider about the current status of a particular token in the following cases:
The Token Status Callback MUST be hosted at the following well known location, relative to the server root of the https origin of the Account Provider in the token.
/.well-known/delegated-account-recovery/token-status
Token Callback endpoints MUST support both the HTTP POST and GET methods.
Support for Token Status Callbacks is optional for both the Account Provider and Recovery Provider.
If an Account Provider wishes to receive Token Status Callbacks it MUST set the status_requested field of the recovery token to 1.
If an Account Provider does not intend to take action based on Token Status Callbacks or wishes to provide additional unlinkability and privacy guarantees for a token it SHOULD set the status_requested field to 0.
The following token lifecycle events can be reported to an Account Provider by a Recovery Provider:
When sending a lifecycle event, the Recovery Provider invokes the well-known endpoint with a application/x-www-form-urlencoded formatted POST body including the parameter id set to the hex-encoded value of the token_id field of the recovery token, and the parameter status set to the literal ASCII string of the status event from the above enumeration. (e.g. save-success or deleted)
If the event being reported is recovery-repudiated the Recovery Provider SHOULD also include a parameter, countersigned_id, set to the hex-encoded value of the token_id field for the countersigned recovery token associated with the recovery action being repudiated.
Because the Token Status Callback is a direct, server-to-server call, hosting this endpoint only at a well-known location reduces the risk of Server-Side Request Forgery.
Although the recommended entropy in the token id should make brute-force of fraudulent events difficult, Account Providers might choose to only request status callbacks from known Recovery Providers and only accept requests from known IP ranges or require additional authentication mechanisms beyond the scope of this protocol to mitigate risks of forgery and denial-of-service with such requests.
A Recovery Token is a credential representing the ability to recover control of an account. It is defined as:
token = base64(token_internals || token_signature)
The internal contents of a token are as follows:
token_internals = struct { uint8 version uint8 type byte[16] token_id uint8 options uint16 issuer_length string issuer[issuer_length] uint16 audience_length string audience[audience_length] unit16 issued_time_length string issued_time[issued_time_length] uint16 data_length opaque data[data_length] uint16 binding_length opaque binding[binding_length] }
The opaque data contains information that the Account Provider needs to validate and restore control of an account, but which should not be shared with the Recovery Provider. It MUST be encrypted to prevent disclosure of its internal structure.
Because it is encrypted and opaque, it may contain whatever information in whatever format the Account Provider feels is necessary and appropriate, but any information beyond that specified for inclusion in the outer token MUST be placed in the encrypted portion and protected from disclosure to the Recovery Provider.
Recovery Providers MAY reject a token that is too large.
The choice of algorithm and key management is left to the discretion of the Account Provider.
A recovery token may still be usable even if an attacker obtains the key used to encrypt the opaque data, (though user privacy may be compromised) but if the Account Provider loses this key (and the ability to decrypt the token data) the account recovery capability will be lost.
token_signature is a signature over the token_internals octet string as defined according to the version field, with the private key corresponding to the public key for the Recovery Provider currently published as part of its configuration.
For this version (0) of the protocol, this is ECDSA over the SHA256 hash of the token_internals octet string. The signature is encoded as DER-encoded ASN.1 structure (a SEQUENCE of two INTEGERs, for r and s, in that order).
A Counter-Signed Recovery Token is a credential representing the Recovery Provider's re-authentication of the account holder who originally saved the Recovery Token it contains. It is defined as:
token = base64(countersigned_token_internals || countersigned_token_signature)
The internal contents of a countersigned token are as follows:
countersigned_token_internals = struct { uint8 version uint8 type byte[16] token_id uint8 options uint16 issuer_length string issuer[issuer_length] uint16 audience_length string audience[audience_length] uint16 issued_time_length string issued_time[issued_time_length] uint16 data_length opaque data[data_length] uint16 binding_length opaque binding[binding_length] }
countersigned_token_signature is a signature over the countersigned_token_internals octet string as defined according to the algorithm field, with the private key corresponding to the public key for the Recovery Provider currently published as part of its configuration.
For this version of the protocol (0), the algorithm is ECDSA over the SHA256 hash of the countersigned_token_internals octet string. The signature is encoded as DER-encoded ASN.1 structure (a SEQUENCE of two INTEGERs, for r and s, in that order)
This protocol, in addition to allowing recovery of accounts in a delegated fashion, may be used to recover other capabilities, like a recovery key for encrypted email or files. For example, the provider of a an encryption service might use a threshold cryptosystem to break a key into several parts, and ask the user to store the pieces (encoded in the opaque data field) as account recovery tokens at several providers. If the user loses their own copy of the key, they can still recover it, but the backup is not subject to server-side compromise by any single entity.
As even slight biases in the selection of the random value k used by ECDSA can lead to a key compromise. As such, implementers SHOULD follow the method described in [RFC5246] for generating deterministic values of k.
Users should be notified, by both the Recovery Provider and Account Provider, whenever a recovery capability is exercised, in order to provide an opportunity to react if they did not initiate the action. Out-of-band means (email, instant message, SMS, etc.) should be preferred to reduce the opportunity for an attacker in control of a user's account to remove such signals.
An explicit goal of this specification is that account recovery operations can be explicitly recognized as high-risk operations and subject to additional authentication controls by a Recovery Provider. Recovery Providers should treat the exercising of a recovery capability as a high risk action and require a high degree of confidence in the user's authentication to perform it. The nature of this is application-specific at each Recovery Provider.
To achieve a convenient and privacy-preserving user experience many Recovery Providers will rely on the ambient authority of the user's browser (e.g. cookies) to associate a recovery token to their account. If an attacker can execute a session fixation attack on a user, in which the user is unknowingly logged out of their account and logged in to a different account under the control of an attacker (e.g. through a logout/login CSRF attack), and then convince the user to save an account recovery token, the attacker may be able to use that to take control of the account for which the token grants a recovery capability.
To mitigate this risk, Recovery Providers should take precautions to prevent Cross-Site Request Forgery against login/logout endpoints. Recovery Providers may also wish to track, for example through persistent cookies, which user agents have been used with multiple accounts, and require additional confirmation that the user is aware of the current logged in user state before saving a recovery token.
This specification does not mandate that a counter-signed recovery token be the exclusive means by which an Account Provider allows restoring control or resetting the credentials of an account. They may treat it as only one authentication signal among many possible or necessary ones. Resetting a high-value account might require, e.g. multiple instances of this protocol to be completed with independent Recovery Providers, or make use of additional authentication factors exclusively at the Account Provider.
Whether to accept or reject a presented counter-signed recovery token is always at the discretion of the Account Provider. Use of this protocol does not imply any contract or obligation to honor any previously saved recovery capability.
The opaque data field can be also be used to encapsulate additional information to use in strengthening the process. For example, a traditional account recovery "secret question" and its answer might be encoded into this data. This implementation reduces many of the risks of such questions, as they cannot be seen or brute-force guessed by an attacker that has not already compromised the user's account at the Recovery Provider, and the content of such question / answer sets cannot leak through a data breach at either the Recovery or Account Provider individually.
If a user recovers their account following a period of compromise, the Account Provider should take precautions to invalidate any new recovery tokens that may have been issued during the compromise period.
Generally, recovering an account is a high-security event, and a key advantage of this protocol is that it identifies recoveries explicitly, so they may have appropriate re-authentication and rate limiting applied by a Recovery Provider.
However, the ability to anonymously attest continuity of control of an account at an external source has other uses beyond recovering account using this protocol as the sole source of evidence.
If an Account Provider sets the "Low Friction" bit in the token options bitflag, it is indicating to the Recovery Provider that the token will not be treated as a single authentication factor, and so request that ease of use in "recovery" be prioritized over additional security measures or strict rate limting. In this mode, the protcol may be used as a generalized part of a multi-factor authentication solution, replacing solutions like one-time passwords with a decentralized mesh of user accounts.
When a Recovery Provider receives a token with the Low Friction flag set, it SHOULD adjust rate limts and re-authentication strategies to prioritize user success and ease of use above the level of authentication assurance. It SHOULD then set the same flag in the Countersigned Token it issues.
Additionally, a Recovery Provider MAY use the Low Friction flag in a Countersigned Token to indicate to an Account Provider that, despite best efforts for a Recovery Token where the Low Friction flag was not set, a strong level of authentication assurance was not possible. It is at the discretion of the Recovery Provider exactly what this means, but suggested that this flag be set when the level of authentication possible was no stronger than username/password. This SHOULD only be used when stronger challenges are not available due to the configuration of the account at the Recovery Provider. If a strong authentication challenge was available but could not be completed, the Recovery Provider should not issue a Countersigned Token.
Many web application endpoints require an unforgeable token be sent as part of any HTTP POST to prevent Cross-Site Request Forgery (CSRF) attacks from abusing the ambient authority represented by cookies or other implicit credentials sent by a web user agent.
Because the architecture of Delegated Account Recovery relies on deliberate cross-origin POSTs, normal protections of this sort cannot be applied to the endpoints specified by this specification.
To prevent abuse, both Account and Recovery Providers should require explicit user confirmation of actions in pages that contain anti-automation measures, e.g. by setting an X-Frame-Options header [RFC7034] or Content-Security-Policy "frame-ancestors" directive to prevent clickjacking attacks.
Initiating sending a recovery token to a recovery provider should be protected against Cross-Site Request Forgery and clickjacking, to prevent users being tricked into sending tokens to fraudulent providers. Account Providers may want to take special measures to require unforgeable user consent or block entirely the delegation of tokens to low-reputation Recovery Providers.
Participants should monitor rates at which recovery capabilities are exercised and rates at which users report unauthorized exercising of recovery capabilities. A high rate of unauthorized recovery actions initiated at a given Recovery Provider may indicate a compromised or malicious provider. Both Recovery and Account Providers should publish contact information for use in incident reporting and response. Verification of token bindings and issued_time freshness should also be performed to prevent disclosed tokens from being re-associated to new accounts at a Recovery Provider.
This protocol relies on comparison of timestamps from different network servers as a defense-in-depth measure to prevent re-use of leaked tokens, in particular re-association of a leaked token with a different account at the same audience server. Although client clock skews are a frequent issue for protocols with such dependencies, this protocol only depends on reasonable clock synchronization between servers, never the user-managed client clock. Participating servers in this protocol should endeavor to issue tokens as close in time to when they will be transmitted as possible and should take steps to reduce their own clock skew, for example, by periodic synchronization with standardized Internet time sources. The specifics of such mechanisms are beyond the scope of this document.
This protocol involves three keys: the public/private key pairs of the Account and Recovery Providers, and whatever key the Account Provider uses to encrypt the opaque data. Additionally, the recovery tokens themselves convey some security capability. The protocol can offer some resilience to loss or compromise of these keys and artifacts.
If the Recovery Provider's key is compromised, it should publicize the window in which it was compromised, and should notify Account Providers with whom recovery capabilities were exercised during the window of compromise. Mechanisms to communicate this are outside the scope of this protocol. If notified by a Recovery Provider of a key compromise, Account Providers should identify recovery capabilities exercised from that provider during the window of compromise and perform additional diligence for the security of those accounts. Generally, if only the Recovery Provider's key is compromised, but not the Recovery Provider's other infrastructure around this protocol (e.g. if a key was generated using weak entropy but other operational procedures were sound) then no attack is possible, since an attacker must have both a genuine recovery token and the counter-signing key to take over a user's account. Rotation of the published key is sufficient to restore trust for the purposes of this protocol. Stored recovery tokens do not need to be re-issued.
If a set of recovery tokens leak from a Recovery Provider, they do not convey any capability without also being countersigned by the Recovery Provider's key, and they by themselves convey no personally identifying information about the account to which they apply. So long as the Recovery Provider's published key remains secure, leaked recovery tokens do not need to be distrusted or re-issued. Verification of token bindings and refusal of tokens with a stale issued_time prior to saving any recovery token can prevent leaked tokens from being re-added to different accounts under an attacker's control at the same Recovery Provider.
If an Account Provider loses control of only its token signing key, this conveys limited capabilities to the attacker. It can cause false tokens to be stored by a Recovery Provider, but only at an account it also controls at the Recovery Provider, and will not have the ability to forge the opaque data. To ensure this resistance, the opaque data field should be encrypted using an AEAD mode or other encrypt-then-MAC construction to prevent it from being malleable.
If an Account Provider loses its data encryption keys, tokens issued under those keys will be unusable.
This protocol depends on TLS, HTTPS and the Web PKI to bootstrap its self-organizing trust framework using HTTPS to distribute keys. Because end-users' communication with the network service providers in question, including transmission of credentials and session management material, also are almost always dependent on TLS and the HTTPS Web PKI, there is little value in attempting to eliminate this as part of the trusted computing base for this specification.
Account and Recovery Providers should be cautious in the management of the root certification authorities they trust when performing configuration discovery operations over HTTPS, should use the latest practical TLS version and should terminate the protocol without user recourse if any errors are encountered. Participants may want to employ additional means to reduce the risk of compromised HTTPS connections that are beyond the scope of this document, such as HTTP Public Key Pinning [RFC7469] and Certificate Transparency. [RFC6962]
It may be possible that recovery tokens leak to third parties. Use of the POST method and endpoints which are either well-known or discovered from the configuration are intended as countermeasures.
Protocol participants should take additional precautions against token leaks in their application-specific logic, such as avoiding moving tokens from POST to GET parameters in cleartext during a login flow prior to saving a token.
Use of a token binding can reduce these risks.
This section is non-normative.
Software platforms may represent Elliptic Curve public keys differently. The configuration encoding required by this specification is the format used by OpenSSL's Elliptic Curve implementation (X9.62 / RFC 3280), which uses the alias "prime256v1" to refer to the NIST secp256r1 curve. Some software only expects a "raw" ECPoint representation as a public key. If your software's EC public key representation is 65 octets long and begins with 0x04, this is a raw ECPoint. Because they are of fixed length, these raw points can be converted to the ASN.1 encoded form required by this specification by simply prefixing the following 26 octets to the buffer:
[48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0]
Future revisions to this protocol may use a registry to map supported cryptographic algorithms to the token version indiator.
The author would like to thank Andrey Labunets, Neil Matatall and Patrick Toomey for their valuable contributions.
properties