top | item 16070394

Show HN: PAST, a secure alternative to JWT

362 points| CiPHPerCoder | 8 years ago |github.com

138 comments

order
[+] tptacek|8 years ago|reply
This is better than JWT. In particular: the whole protocol is versioned, rather than serving as a metaprotocol that negotiates the underlying cryptography. If you speak "v2" of this protocol, and refuse to accept any other version, then you're getting a token that is basically just Nacl.

My only nit --- apart from the "auth enc seal sign" names, which aren't coherent --- is why do public key at all? Yes, Nacl supports it, but that doesn't mean the token format does. What's the use case for it? Who's asking for it? Specifically who? The overwhelming majority of JWT implementations I see aren't public key (except for the fact that the format is negotiated and might be tricked into being that).

Why not punt "seal" and "sign" into a "v3", when/if it's needed?

[+] eadmund|8 years ago|reply
We use public-key JWTs so that the verifying servers do not have a copy of the secret key, just the authorisation server's public key. That prevents a compromise of the verifying servers from also compromising the entire system (yes, a compromised verifying server can be made to do anything it's allowed to do — but that's still less than everything).
[+] CiPHPerCoder|8 years ago|reply
> My only nit --- apart from the "auth enc seal sign" names, which aren't coherent --- is why do public key at all?

> Why not punt "seal" and "sign" into a "v3", when/if it's needed?

Would you be happier seeing something like this?

  - v1: HMAC-SHA2, AES-CTR+HMAC-SHA2
  - v2: RSA and all its sins
  - v3: Libsodium crypto_aead_*
  - v4: Libsodium crypto_{box,sign}_*
> What's the use case for it? Who's asking for it? Specifically who?

The only use-case I'm aware of as of this morning is OAuth2 users who currently use JWT for access tokens. https://bshaffer.github.io/oauth2-server-php-docs/overview/j...

[+] blattimwind|8 years ago|reply
> In particular: the whole protocol is versioned, rather than serving as a metaprotocol that negotiates the underlying cryptography.

In my view, that's one of the big takeaways from early cryptographic protocols: complex handshake negotiations just won't be secure, so just don't. The other is that crypto code should ideally not contain any parsing at all.

e: Well that and the whole debacle on the level of primitives and operation modes of course.

[+] cmsd2|8 years ago|reply
really? both Azure AD and AWS Cognito use RS256 as the only algorithm supported. perhaps my sample size is small.
[+] lvh|8 years ago|reply
This is great. Having versions instead of kitchen sinks, and having those versions get rid of the footguns, is exactly what fixes the cryptographic JWT perils.

Note: you probably still just want a random key in a database. And revocation is still an issue. But if you’re absolutely sure you want to mint tokens...

[+] saganus|8 years ago|reply
What is a use case for minting tokens and one for not minting?

I've seen this referenced a few times before but I don't understand why minting tokens is bad.

Also, isn't creating a random key as a token the same as minting one? or what is the correct context here for "minting tokens"?

Thanks!

[+] allyant|8 years ago|reply
Just a small 'way forward' for those wanting to have the ability to revoke a JWT after I came up with a solution on my last project: A 'Gateway' - use OpenResty to verify the JWT ID stored in a redis cache using a proxy pass. When the Authentication service grants a JWT add its ID to this cache along with a way of identifying the user. That way the entire advantage/disadvantage of decentralised authentication is not fully weakened and OpenResty + Redis can be relatively fast.
[+] pinguinFromY|8 years ago|reply
You blacklist your tokens in a cache and that's all.
[+] zeveb|8 years ago|reply
> you probably still just want a random key in a database.

In general, I think that this is the wrong approach, because that means adding a database round-trip (which in a large system is almost certainly a network round-trip) for each and every API call. Notably, if the entire system is secured in depth (which large systems should be), it means adding a network round-trip for every layer of the API (e.g. one for the frontend server to validate the user, then another for a backend server to validate the frontend server). Using a stateful token[0] replaces that network round trip with a public-key or hash verification, which is much faster.

> revocation is still an issue

I think that generally revocation concerns are a bit overblown. Even with a database lookup on every request, there is a (small) amount of time that one is willing to act on out-of-date information (after all, the user's access could be disabled immediately after the lookup, before the action is performed). Almost every business has some window in which it is willing to act on old information: better to make it explicit than to leave it implicit.

I really like the long-lived stateless token-refresh token[1] and relatively short-lived stateful access token approach often seen in OAuth2 setups. E.g. an email provider might only bother refreshing a read-email access token every five minutes or so, but might wish to refresh a delete-email or send-email token more frequently (or require a database lookup each time).

[0] When I write 'stateful token,' I mean a token which is full of state; confusingly, some folks calls this a 'stateless token,' because the relying systems do not need to store or consult state.

[1] When I write 'stateless token,' I mean a token which carries no state and thus must be looked up in some form of database — a random key in a database would suffice.

[+] lxe|8 years ago|reply
I really don't get the whole "the spec supports choosing of algorithm, therefore the whole implementation is bad"

If my server-side application sends a JWT with a "good" algorithm, and disallows any other alg's, wouldn't that prevent attacks?

Why do we need a whole new implementation?

[+] level|8 years ago|reply
The problem is that it's not idiot-proof. If someone doesn't understand why the algorithm is important, they might choose none. It's easy to say "they shouldn't be using JWTs if they don't know how to use them", but everyone starts somewhere, and everyone puts stupid bugs into production.

JWT is safe, as long as it's setup correctly, but safe-by-default is a better option.

That being said, I'm not going to swap out my JWTs with PASTs. I know what algorithm I'm using, why I'm using it, it is safe, and I'm verifying them properly.

[+] JepZ|8 years ago|reply
I am totally with you. For me JWT is the idea to store encrypted values client-side which you can use to authenticate the client and is different to the old way of just storing a random 'dumb' session id with the linked values somewhere on the server.

So yes, I appreciate secure and easy-to-use implementations of that idea, but always going for how insecure JWTs are, just because there are easy ways to do it wrong, is like telling everybody that password logins are bad because some people implemented them in flash.

> Why do we need a whole new implementation?

I think the problem which many people have with JWT is that is not strict enough and does not define certain things. PAST uses the same idea, but does not allow that wide variety of different algorithms we could use with JWT. In my eyes it makes it easier to use, because you do not have to search for implementations with compatible and secure algorithms but just for implementations using the latest version of PAST.

[+] duskwuff|8 years ago|reply
> If my server-side application sends a JWT with a "good" algorithm, and disallows any other alg's, wouldn't that prevent attacks?

It does not. Unless you have specifically hardened your server to refuse to even try verifying tokens which use "bad" algorithms, a client can still present a key signed with one of those algorithms, and attempting to verify it may pose a risk.

[+] treve|8 years ago|reply
I think one of the issues is a very practical one. When everything is called JWT, it's hard for users to figure out whether it's a secure or insecure implementation.

It's completely possible to do secure things with JWT, especially if you control every producer and consumer, but it's not guaranteed.

[+] WorldMaker|8 years ago|reply
There's also the issue that the alg field is in an encoded section of the JWT payload and has to be base64-decoded and then JSON parsed. There have been buffer overrun and malicious JSON attacks on JWT.

PAST at least moves that to a clear text prefix in the vx.scheme pattern. Theoretically, that doesn't even stop it from having a v0.none or some other dumb algorithm such as JWT allows in a bad version suite, but it does at least mitigate against decryption attacks.

[+] atonse|8 years ago|reply
I have implemented JWT on my app but the library I used (Guardian, written in Elixir), only allows you to use HMAC-SHA512 by default. And I've left it that way.

Should I still be worried? I get that JWT's algorithm flexibility is overall a bad thing, but if I only allow one, should I continue to worry?

[+] lvh|8 years ago|reply
I haven't reviewed said library, so I'm taking your word for it that it's actually limited to that suite :-) The problems with JWT are more complicated than just negotiation, but you should be OK here.

Here's why:

- Some bugs are about negotiation, e.g. key material misuse between RSA and HMAC schemes. They don't affect you, because you don't negotiate.

- Some bugs are about cryptographic implementation, such as not reusing nonces for ECDSA. They don't affect you, because _HMAC-SHA256_ doesn't have most of these problems.

- Some bugs are about specification issues, such as non-mandatory aud (audience) and exp (expiry). Audience shouldn't be a problem for you, because the only audience is you and there's only one secret key, so you get automatic audience restriction via cryptographic binding. Expiry, well, that's on you.

Why did you use JWT to begin with? (What does minting tokens buy you?)

[+] idbehold|8 years ago|reply
I do wish a different acronym had been chosen. When I search for "[language of choice] JWT" pretty much all results are relevant. But even if this new token schema takes off it will forever be a hassle to find relevant results for "[language of choice] PAST".
[+] CiPHPerCoder|8 years ago|reply
I spent two weeks (my Christmas vacation) working on rough drafts for several problems I wanted to solve in 2018. PAST was one of items I listed.

(The list is here: https://github.com/paragonie-scott/public-projects/issues/6)

99.9% of that time was spent trying to come up with a better name/acronym, without success. I decided to just give it a plain/obvious name until a better one surfaced.

[+] Daycrawler|8 years ago|reply
This doesn't solve the criticism against JWT being used for sessions, which is one of the main point against JWT expressed in the very site linked at the top of the README.
[+] CiPHPerCoder|8 years ago|reply
There's nothing I can do at this layer that will stop people from using JWT/PAST/etc. as an attempt to build stateless session management systems for some ill-conceived "horizontal scalability" requirements, except maybe continue to tell people this is a bad idea and don't do that.

The rest of the points (i.e. the problems with the JOSE standards) are what PAST seeks to solve. The "do not misuse" problem is more complicated, and if I were to add e.g. "do not use this for stateless sessions" at the top in big red letters, that will only tell developers "this is unsafe, keep using JWT instead".

[+] Lazare|8 years ago|reply
This looks promising, and it's from a very well respected security researcher.
[+] waibelp|8 years ago|reply
This library is a great example of clean and beautiful php code out in the wild!
[+] tootie|8 years ago|reply
I don't get it. We used to use something like a pipe-delimited string, then JWT, now PAST. Isn't the encryption doing all the work regardless of how the data is structured?
[+] lvh|8 years ago|reply
Getting the encryption right is pretty tricky! How do you verify the encryption method for a message, for example? That's a real problem in JWT: that's how RSA privkeys leak. PAST solves this by not negotiating. How do you make sure nobody's doing nonce reuse in ECDSA? That's a real problem in JWT. PAST solves this by only having (v2) specify exactly how to do that.

Just because this specifies a format, doens't mean it's just a format :)

[+] timwis|8 years ago|reply
A common security issue I've seen with uses of JWT doesn't have to do with JWT itself but how it's used by front-end developers. It's commonly stored in localStorage instead of an HttpOnly cookie, which creates a cross-site scripting vulnerability.

More details here: http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-fo...

Shockingly, the advice I've seen to protect against this by folks like Auth0 is "keep your tokens expiration low" or not mention it at all.

I don't imagine PAST gets around this, as it's more like misinformation around the storage mechanism, but I think it's worth mentioning in any "how to use" section about PAST or JWT.

[+] lvh|8 years ago|reply
If something is a HttpOnly cookie, and I get XSS, why can't I just hit your API as much as I like anyway?
[+] k__|8 years ago|reply
I had the impression that the main problem was that JWT was marketed as stateless and superior and then you were stuck with stolen tokens.

How does PAST solve this? Is it even possible to get secure stateless auth?

[+] MrCalifornian|8 years ago|reply
Why not propose changes to the RFC instead of creating a new standard?
[+] partycoder|8 years ago|reply
"A secure alternative". Citation needed.
[+] cheez|8 years ago|reply
I'm not a security expert but when I looked into JWT I was terrified at how easy it was to screw up. Glad to see I'm not the only one.