
Managing a Secure JSON Web Token Implementation - fanieldanara
https://cursorblog.com/managing-a-secure-json-web-token-implementation/
======
unscaled
If you are going to use JWT besides its failings, you should use it safely.
But not all advice in this piece is equally strong.

1\. RS256 vs ES256 - you shouldn't use either. RS256 not just an old standard
on the way out. With safe keys sizes tokens are often going to be too large
and signing too slow for you. ES256 on the other hand, suffers from many
theoretical flaws and at least one practical flaw that (complete breakdown if
nonce is reused) that helped jailbreak the PS3.

The only reasonable asymmetric signature algorithms implemented for JWT are
Ed25519 and Ed448, but they are still not supported by most libraries.

2\. Key IDs - always include them, even if you're just using 1 key for now.
Otherwise you cannot rotate keys securely without having to reject all
existing tokens.

3\. Have relatively short lifetimes for JWTs if you're not using a blacklist.
A token that lasts for 180 days with no possible way to revoke it is a
dangerous little thing.

4\. Always verify that you only accept JWTs signed by the algorithm you're
expecting. Otherwise you might be fooled by a JWT signed with HMAC-SHA256 by
your RSA public key (which is known to the attacker:
[https://auth0.com/blog/critical-vulnerabilities-in-json-
web-...](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-
libraries/#RSA-or-HMAC-)

5\. Under no circumstances accept tokens signed with "none". The standard is
just bonkers.

6\. Rotate keys every month if you can, not every 2 years. This is keeping
your joints well-oiled.

7\. Damage control is still possible when using JSON Web Signature (JWS). JSON
Web Encryption (JWE), on the other hand, is just a train wreck that is very
hard t ouse properly. Avoid it all costs. PASETO provides a viable alternative
for most cases it makes sense to use an encrypted token.

8\. If you can avoid JWT, just avoid it. It's just too hard to implement
securely. In the past there weren't any widespread alternatives, but PASETO is
supported in most common platforms now and is clearly a better option.

[https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-
ba...](https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-
that-everyone-should-avoid)

~~~
jakecraige
Nonce reuse is easily preventable with deterministic nonces or sufficient
randomness. PS3 used a fixed nonce which is a whole different problem.

I agree that JWT has all sorts of flexibility that make it hard to use well
but NIST curves work just fine.

If you think they are backdoored then sure, Ed25519 is a better option but
real world constraints may require you to use a NIST curve for now.

~~~
unscaled
I don't think the NIST curves are backdoored, but they obviously have some
serious theoretical and practical issues. [1]

As far as I know, neither of these issues is relevant to their usage with
ECDSA (although invalid curve attacks should be a good enough reason to avoid
using these curves with ECDH completely), but experience with SHA-1 and RC4
has thought us that algorithms with theoretical problems are likely to be
practically broken sooner or later.

But NIST curves are not even the main issue with the ES __* algorithms in JWT.
The real issue is ECDSA:

1\. Verification is slow. P-256 is about 2-4 times slower than Ed25519 [2].
This kind of speed hit may often be unacceptable. 2\. Nonce reuse is an issue.
The PS3 implementation was extremely bad, but random number generators can
often be broken. This is not a theoretical issue - it used to happen verify
often with docker containers until recently. There are alternative schemes
that allow using ECDSA with a deterministic synthetic nonce [3], but this is
not supported by any JWT implementation I know of. Ed25519, on the other hand,
uses a synthetic nonce.

[1] [https://safecurves.cr.yp.to/](https://safecurves.cr.yp.to/) [2]
[https://bench.cr.yp.to/results-sign.html](https://bench.cr.yp.to/results-
sign.html) [3]
[https://tools.ietf.org/html/rfc6979](https://tools.ietf.org/html/rfc6979)

------
merlincorey
Anyone have any experience implementing PASETO[0]?

I have read the papers and seen the talks -- it seems fairly compelling.

[0] [https://paseto.io/](https://paseto.io/)

~~~
return_0e
I haven't implemented PASETO but I was thinking about adding support for
another language. If I were to implement it, I would just use libsodium for
most of the cryptographic primitives whenever possible since the reference
PASETO implementation uses it as well as most of the other language
implementations too (Except for the Go version).

PASETO does seem like a cryptographic secure alternative that addresses the
pitfalls of the JOSE standard and has most of the mitigations mentioned in
this blog-post (No cryptographic-algorithm agility) and it supports the same
functionalities of JWT/JWE and JWS. So I am convinced on getting that
standardized, but it also needs XChaCha20-Poly1305 AEAD to be standardized too
[0].

Fernet was also around as being a secure alternative, but it has been mostly
replaced by Branca [1] and PASETO.v2.

[0] - [https://github.com/bikeshedders/xchacha-
rfc](https://github.com/bikeshedders/xchacha-rfc)

[1] - [https://branca.io](https://branca.io)

------
indeyets
As long as all supposed consumers of JWT are on my infrastructure I prefer to
make all tokens revokable. Tokens TTL is smaller than 1 hour so I keep 1 hour
worth of revocations on all servers (pushed via queue). If key is on list it
is refused (without database hits)

------
mittermayr
Now, what is the (currently accepted) best way to store that refresh token in
a ReactJS frontend? I send the JWT via Cookies as “httpOnly; Secure”, would
the refresh token go the same route? If so, wouldn’t compromising of the JWT
also mean the same for the refresh token? And therefore give the person
unlimited access until key-rotation?

Or, like with Oauth2, is the idea that JWT gets transmitted back to the server
with every request, and the refresh token only when needed and therefore
having a slightly smaller risk of intercepting both keys (assuming the refresh
token is not stored in cookies)?

~~~
FlorianRappl
You should not store any token in the frontend. Instead, have a server doing
that and use a classic secure cookie session. The session is bound to the
token / refresh token and can then do the token management.

Alternatively, don't use access token / refresh token but an ID token. The
refresh of the token will be done via the ID token and the user's session
(cookie) to the OAuth provider.

~~~
spydum
Agree this stuck out to me - I think a lot of confusion stems from how to
handle refresh tokens - the oauth spec I feel is responsible by the confusion
of how it calls apps “clients” and how flimsy it is about implementation
(should/shall/must). If you are keeping refresh token locally on the user
agent, you really urgently need to provide the user session management tools
to revoke those things, and you need to be doing more advanced threat/abuse
detection of their usage.

~~~
cormacrelf
Most people should probably follow the pathways laid out by IdentityServer4
and oidc-client, even if not not using .NET Core (you could absolutely deploy
it standalone). Lots of sane defaults, even for refresh tokens and revocations
and other difficult specs to understand. It’s well maintained and well thought
out.

------
kyriakos
When is the refresh token meant to be expiring? Can't the man in the middle
just use the refresh token to get a new valid jwt?

~~~
thangngoc89
From the article, refresh tokens are revokable. The whole point of JWT +
refresh token is that for normal operation, you don't need to hit the database
but still able to revoke a token.

