Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jti requirements for replay prevention #32

Closed
b---c opened this issue Apr 8, 2019 · 10 comments
Closed

jti requirements for replay prevention #32

b---c opened this issue Apr 8, 2019 · 10 comments

Comments

@b---c
Copy link
Collaborator

b---c commented Apr 8, 2019

https://tools.ietf.org/html/draft-fett-oauth-dpop-01#section-11.2 has

11.2.  Token Replay at the Same Resource Server Endpoint

   If an adversary is able to get hold of a DPoP-Proof JWT, the
   adversary could replay that token later at the same endpoint (the
   HTTP endpoint and method are enforced via the respective claims in
   the JWTs).  To prevent this, clients MUST limit the lifetime of the
   JWTs, preferably to a brief period.  Furthermore, the "jti" claim in
   each JWT MUST contain a unique (incrementing or randomly chosen)
   value, as proposed in [RFC7253].  Resource servers SHOULD store
   values at least for the lifetime of the respective JWT and decline
   HTTP requests by clients if a "jti" value has been seen before.

However, the "(incrementing or ...)" part might be problematic and lead to collisions and false positives on replay checks if jti alone is what is stored and checked server side when multiple clients (even instances of clients) are incrementing from the same or similar values for jit. The server would need to track jti values qualified by the public key or something. And I'd think at that point it'd be easier to just say to track the whole JWT (or a hash thereof) for replay prevention.

Or drop the "incrementing" part for jti and also have a minimum suggested or required entropy for unlikelihood of collisions globally. Probably 128 bits - i.e. 16 secure pseudorandom bytes that are base64url encoded gives something like "jti": "_ltc11acc9_ESC4bwc3u-8"

I guess the https://tools.ietf.org/html/rfc7519#section-4.1.7 definition of jti really kind of says that already. But I think people will see "incrementing" and potentially get it wrong. So some guidance might be useful. At least removing ""incrementing".


   The "jti" (JWT ID) claim provides a unique identifier for the JWT.
   The identifier value MUST be assigned in a manner that ensures that
   there is a negligible probability that the same value will be
   accidentally assigned to a different data object; if the application
   uses multiple issuers, collisions MUST be prevented among values
   produced by different issuers as well.  The "jti" claim can be used
   to prevent the JWT from being replayed.  The "jti" value is a case-
   sensitive string.  Use of this claim is OPTIONAL.
@dwaite
Copy link

dwaite commented Apr 9, 2019

The time that the token is valid needs to be scoped as well to limit the replay cache. Perhaps a recommendation on the limit, having the limit set by the AS in metadata and the AS/resources having an error code for rejection should the exp be too far in the future?

@panva
Copy link
Contributor

panva commented Apr 9, 2019

BTW private_key_jwt and client_secret_jwt client assertions could also use such recommendation / negotiation on the jti/exp cache limits

@b---c
Copy link
Collaborator Author

b---c commented Apr 9, 2019

private_key_jwt & client_secret_jwt do have the following in bullet 4 of https://tools.ietf.org/html/rfc7523#section-3

   Note that the authorization server may reject JWTs
        with an "exp" claim value that is unreasonably far in the
        future.

which gets the idea across but is light on specifics.

@danielfett
Copy link
Owner

Agree, incrementing is error-prone. There is no harm in just using a fresh random value each time.

I am wondering if we need an exp claim at all, or whether iat would be enough. The AS/RS could publish the maximum age for a DPoP token (a few seconds?) in its metadata, but it should not matter too much, since the client will just generate a new token each time.

@panva
Copy link
Contributor

panva commented Apr 11, 2019

iat would have to be validated NOT to be in the future on the AS/RS and we'd get into clock skew issues. exp is in my opinion better so long as the recipient can reject it if it's too far in the future in order to maintain the replay cache.

@dwaite
Copy link

dwaite commented Apr 11, 2019 via email

@panva
Copy link
Contributor

panva commented Apr 11, 2019

It is more intuitive to set exp to 30 minutes knowing i won't be re-using the token anyway when the recipient supports a value this "long". On the other hand it's not intuitive (or sometimes possible with JWT libraries) to set iat to 5 minutes ago just to satisfy iat not being "in the future" and a reasonable clock skew.

@tlodderstedt
Copy link
Collaborator

to me, it feels more intuitive to use exp since the client controls the expiration that way. iat moves that to the AS/RS, which feels contra-intuitive in this particular use case.

@dwaite
Copy link

dwaite commented Apr 11, 2019

I'll assume the conversation is discussing a difference between a nbf/exp pair and iat.

To make a case against iat/exp or nbf/exp:

  • if it is the iat/exp pair, then the AS or RS may need to accept tokens slightly before their issued time to deal with clock drift anyway - or the client alters their 'iat' to be before the actual 'iat'
  • if it is a nbf/exp pair, the JWT spec still allows the recipient to adjust for clock drift. The JWT spec allows for 'a few minutes'
  • The expiration policy is is still in the AS/RS control - if they don’t like the expiry chosen by the client they will reject it. If they evaluate the nbf/exp as too large of a window they will reject it.
  • sending two values is larger.

On the flip side, sending two values allows the client:

  • to be more explicit on the terms of the proof
  • to be stricter than a AS/RS policy (assuming AS/RS clock drift policy is mutually understood)

My personal opinion? just iat is fine for proof, but nbf/exp may be better for a future case involving non-repudiation.

@danielfett
Copy link
Owner

I support iat instead of exp.
We continue the discussion in #38

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants