Flint (RocketDesk)
2016-04-09 23:33:40 UTC
We are implementing the experimental RFC 7592 in our distributed ASP.NET Core OAuth2 farm. Based on our experience to date, we have a few concerns and suggestions to add to the conversation. Hopefully these are helpful.
[P.S. Generally the RFC is strong. Kudos to the RFC 7592 authors.]
1. Storage of Client Secrets
The concern
RFC 7592 requires that servers store client secrets; for most scenarios this requires that the secrets are effectively stored in plain-text.
For clients using the Authorization Code or Resource Owner Password Credentials grants, this is unfortunate but possibly workable-because the effects of client id + client secret compromise are somewhat minimal--and also because all client ids can be quickly revoked after an OAuth2 server is known to be compromised.
Unfortunately, for many high-trust server-to-server APIs which use the Client Credentials grant, compromised client secrets can be catastrophic (similar to a super-powerful password being leaked).
Furthermore, there is almost always a gap in time between which a server is compromised and detection of the compromise. With the client secrets exposed as plain text, severe damage can be done rapidly to servers, users and data before detection.
Suggestions
1. OAuth2 servers should allowed (or encouraged) to storage client secrets as hashed values. With sufficiently-long crypto-randomly-generated client_secrets, an SHA256 hash should provide strong protection without a requirement for salt.
2. In the Client Read Request, the server should be allowed to return "client_secret_suppressed: true" or something similar in the response as a substitute for "client_secret: value".
2. Non-idempotent nature of Client Read Request
The concern
RFC 7592 permits the server to change the client secret and registration access token when responding to the Client Read Request.
This makes the GET call non-indempotent and can cause serious issues for clients, particularly clients which are statically configured such as those using the Client Credentials grant type. An interrupted or duplicate GET request can quickly result in a client which is unable to further modify or delete its registration.
Of course, non-idempotent GET requests are generally discouraged in REST-like architectures for this sort of reason.
Suggestion
If refresh of the client secret or registration access token is required for an implementer, a POST call with REFRESH action might be a more reliable way to implement this mechanism, similar to the OAuth2 refresh token flow. The older client secret and/or registration token could live for a short period of time (perhaps a few minutes) after the new credentials were issued or until the new credentials were used, as a safety mechanism, if desired.
3. Scenarios where registration access tokens are revoked because of actions by third parties
The concern
RFC 7592 recommends that registration access tokens be revoked when requesting read access to a non-existent client registration.
Given a sufficiently-long token with sufficient entropy, it is mathematically unlikely that an attacker would use valid tokens to try to get access to invalid client registrations. But given enough time, an attacker could effectively destroy the ability for the not-at-fault client to modify or delete its own registration.
Additionally, if an attacker has the registration access token for a valid client and tries to use it to get access to another client, would another (or a more) appropriate action be to revoke the client_id belonging to the registration access token as well?
Suggestion
This is a hard scenario to address, and is simply mentioned to spur further discussion.
[P.S. Generally the RFC is strong. Kudos to the RFC 7592 authors.]
1. Storage of Client Secrets
The concern
RFC 7592 requires that servers store client secrets; for most scenarios this requires that the secrets are effectively stored in plain-text.
For clients using the Authorization Code or Resource Owner Password Credentials grants, this is unfortunate but possibly workable-because the effects of client id + client secret compromise are somewhat minimal--and also because all client ids can be quickly revoked after an OAuth2 server is known to be compromised.
Unfortunately, for many high-trust server-to-server APIs which use the Client Credentials grant, compromised client secrets can be catastrophic (similar to a super-powerful password being leaked).
Furthermore, there is almost always a gap in time between which a server is compromised and detection of the compromise. With the client secrets exposed as plain text, severe damage can be done rapidly to servers, users and data before detection.
Suggestions
1. OAuth2 servers should allowed (or encouraged) to storage client secrets as hashed values. With sufficiently-long crypto-randomly-generated client_secrets, an SHA256 hash should provide strong protection without a requirement for salt.
2. In the Client Read Request, the server should be allowed to return "client_secret_suppressed: true" or something similar in the response as a substitute for "client_secret: value".
2. Non-idempotent nature of Client Read Request
The concern
RFC 7592 permits the server to change the client secret and registration access token when responding to the Client Read Request.
This makes the GET call non-indempotent and can cause serious issues for clients, particularly clients which are statically configured such as those using the Client Credentials grant type. An interrupted or duplicate GET request can quickly result in a client which is unable to further modify or delete its registration.
Of course, non-idempotent GET requests are generally discouraged in REST-like architectures for this sort of reason.
Suggestion
If refresh of the client secret or registration access token is required for an implementer, a POST call with REFRESH action might be a more reliable way to implement this mechanism, similar to the OAuth2 refresh token flow. The older client secret and/or registration token could live for a short period of time (perhaps a few minutes) after the new credentials were issued or until the new credentials were used, as a safety mechanism, if desired.
3. Scenarios where registration access tokens are revoked because of actions by third parties
The concern
RFC 7592 recommends that registration access tokens be revoked when requesting read access to a non-existent client registration.
Given a sufficiently-long token with sufficient entropy, it is mathematically unlikely that an attacker would use valid tokens to try to get access to invalid client registrations. But given enough time, an attacker could effectively destroy the ability for the not-at-fault client to modify or delete its own registration.
Additionally, if an attacker has the registration access token for a valid client and tries to use it to get access to another client, would another (or a more) appropriate action be to revoke the client_id belonging to the registration access token as well?
Suggestion
This is a hard scenario to address, and is simply mentioned to spur further discussion.