PASETO looks excellent to me, in that it's proper developer friendly and makes it hard for non crypto nerds like me to shoot themselves in the foot. I can't wait for it to replace JWT in popularity.
That's nice and all but standards exist for a reason. You ask devs to use it in order to be compliant. Regardless of merits, you can't ask people who are not knowledgable about crypto to use a library by some guy/corp just because you think it has better merits. I mean, I guess you can and some will listen but only a few. Most webdevs for non-web businesses are happy to go with a standard so if something goes wrong they don't get blamed for picking it. And many security/vulnerability pros agree with that line of thinking as well.
In practice,if paseto is better I think an internet draft is in order. If JSOE is bad by commonly accepted security measurements then shouldn't the ietf wg have a mailing list where these shortcomings can be discussed and fixed?
Great article and I agree with all of the criticisms.
There is a big problem with internet standards where the "division of thought" leaves a gap in the middle. The standard author thinks "I am just designing a template for people to follow, it's up to the implementor to consider whether what they're doing actually makes sense for their use-case" and the person implementing that standard thinks "I have implemented it exactly as described, therefore all uses must be sane/secure/whatever".
It specifies a pattern for signing and verifying HTTP requests. You can choose what headers to include in the signature. Now "obviously" any implementation of this standard should require you to specify up-front what headers clients must include in the signature for a request to be valid, but the specification does not mention this at all in the verification section, and none of the reference implementations actually allow you to do this! So as an attacker, I can craft any request I want and just tell the server "I'm not including any headers in the signature".
Similarly: you can include the date header in the signature to help prevent replay attacks, but nowhere does it say that you probably want to check that the date on the request is actually within some threshold of the current time.
And again: you can include the message digest in the signature, but nowhere does it say that you should actually verify that digest against the body. Worse, message digests are an entirely separate spec and no constraints are given about what digest algorithms should be used (many of them are not designed to be cryptographically secure). On top of that, message digests only make sense on requests with a body, so even if your library has support for "require certain headers to be present", there is likely no way to only enforce that a digest header is present for requests with a body.
The "division of thought" you talk about is the opposite of "opinionated" designs/standards.
The former assumes that the reader is going to take their time, think about their own implementation and their own specific use case, and make several careful decisions about how to make it work.
The latter assumes that ain't no reader got time fo dat, and is going to try to npm install any packages that have the same name as keywords in the title of your standard and assume that they're fine.
Development these days is unfortunately slanted towards the latter at a lot of companies who only measure output on number of features you've shipped or the impact of products you've launched, so every incentive there is to ship things as soon as you can.
However, there's no field in package repository metadata that says "this package has sharp edges, use with care" or "this package comes with safe defaults, but use with care nonetheless".
Not so sure - you can design things unopinionated but still have them secure. As an analogy, the whole point of statical typing is to allow all sensible programs to be written while keeping out everything that contradict itself. I.e if the PASETO were a type and an implementation a program then you wouldn't be able to write an implementation that would adher the type but would be insecure. Doesn't appear to be so with JWT and co.
regarding verification; checking the presence of specific headers, and checking that the date falls within a certain window, and checking a Digest... are all good things to do. It's not so difficult to do them yourself, even if the spec doesn't require it. You could say the spec doesn't go far enough.
Apigee (API Gateway) has an HTTPSignature verification callout that does all of those things. You just need to configure it.
> invites developers to come up with clever explanations and workarounds instead of careful engineering
I don't like the accusative tone when talking engineering. There are plenty of good reasons not to use server-side sessions, including the need to replicate them between nodes, or otherwise offload them to an external database, and if you do it asynchronously you have to make your clients sticky. People use JWT to achieve statelessness, which makes it easier to increase availability.
> I don't like the accusative tone when talking engineering.
That's fair.
I wrote this in 2017 to give a single page arguments against the JOSE standards. The accusative tone is required by the fact that the entire page exists to attack the standard, based on technical arguments.
The target audience of the Paragon Initiative blog has always been "PHP developers", and PHP gives you a built-in session mechanism. Which, if you're writing PHP, you should just use. Session security in modern PHP boils down to "use HTTPS".
If you're doing some massively distributed system (the likes of a FAANG company project), you can disregard the advice aimed at LAMP stacks.
Name a security standard written by some one other than DJB that doesn't recommend bad defaults. It's almost as tho a three letter agency with more money than sense is just paying people to write weak standards.
Just because the security idea can and is done poorly doesn't mean that the idea is inherently insecure. We need to see security as an ongoing process not a one time fire and forget thing.
Security like encryption always gets weaker it doesn't get stronger. It's a bad idea to dismiss JWT or similar because the standard has gotten weaker as our understanding gets better.
TLDR: Use PASETO [0] or its simpler alternative Branca [1].
JWT/JWS/JWE are classic examples of bad standards that the industry has chosen to adopt because everyone else is using it. It is a downgrade in terms of usability, cryptography and even in some cases performance. As for sessions, just don't even think about using it with that.
Just use PASETO [0] or Branca [1] tokens which are clearly both actively worked on secure alternatives to JWT which make it harder to shoot yourself in the foot with usability.
> If you need some bizarre stateless property for horizontal scaling your sessions...
> It is overwhelmingly likely that you do not needed crazy horizontal scaling schemes at all, and that a single server-side session management system is sufficient for your use case...
This feels quite short-sighted to me, even in 2017. Architecture for supporting highly available systems and so-called "crazy" horizontal scaling are not so different from each other, and pretty much everyone can benefit significantly from a highly available and fault tolerant architecture.
Stateless application architecture is significantly helpful in keeping a system simple and easy to deploy, which has huge impacts on overall development processes, ability to remediate vulnerabilities and ability to respond to changing requirements.
What are the problems that haven't been solved? Stateless application servers have been reasonably commonplace for years, now, which is the main hurdle that I've needed to surmount. The majority of other issues can be handled at the platform level.
It's a lot of work to refactor an application, and sometimes that doesn't make sense, but a blanket dismissal of the usefulness of proper architecture because an application isn't running at Google or Facebook's scale does little to help push technology and practices forward.
While I understand that complexity in standards might be bad because they allow you to shoot yourself in the foot, I am definitely not going to stop using JWKs with JWT/JWS, those formats are actually quite simple and have allowed us to deploy authenticating proxies essentially everywhere instead of network based access control (which was always kind of broken), with slow key rotation included (thanks keycloak)
Libraries should require the user to use pinned algos. Period.
Not everything is a green field. Yes, I get to deal with SAML a lot, and with how quirky and incomplete and outright non-standard compliant some implementations, particularly for SaaS services are (and how there are always guides for Auth0, Otka and maybe ADFS, but never in plan SAML 2.0 terms), but we also use OIDC for a few more modern services, like Kubernetes and our own proxy and the amount of troubleshooting required has been essentially zero.
One of the goals of the PASETO project is to eliminate the use of JWT in modern standards, not to eliminate the standards that currently (but hopefully, temporarily) use JWT.
Sure JOSE is bad but the author gives no real alternatives to JOSE. A session cookie has little in common with JOSE. The author ignores the need for SSO and distributed authentication. The idp is free to use whatever algo it wants even if it's not in the algo list from the linked RFCs. Whoever wants to authenticate can surely implement the given algo(Most likely it just needs to import it from a standard library.)
I can't find the specification/rfc of Paseto. It looks more of a php lib. To me it seems the author is not familiar with JWT[0] and tries to solve the wrong problems(e.g assumes the idp or library being used are compromised.)
[0]
>> This decodes to:
Version: v2
Purpose: local (shared-key authenticated encryption)
Payload (hex-encoded):
JWT has an 'aud' param that serves the same purpose as "Purpose" here and more.
Versioning makes it even worse and doesn't solve any security issue. If v1 is compromised the client should not be allowed to use it.
> To me it seems the author is not familiar with JWT[0]
How does one demonstrate familiarity with JWT beyond analyzing/critiquing the RFCs for JWT and correlating the specific language of the standard with real-world vulnerabilities of JWT implementations?
> and tries to solve the wrong problems(e.g assumes the idp or library being used are compromised.)
From your two comments, it's clear you skimmed the text you're trying to discuss here. How can your opinion be regarded as relevant in any way? You highlight that author is not familiar with something (he is, he's actually well respected expert who explains everything in fine detail), yet you've shown you don't read carefully at all.
I found PASETO's website, rfc and github within.. 3 seconds of using my PC. I'm 100% sure you're capable of doing the same.
Your comment looks like unnecessary criticism because you feel provoked since someone criticized a piece of technology you use.
Let me ask you this: wouldn't make more sense to publish a rfc for a more strict JOSE (i.e only secure alg; no "none" option etc) and at the same time develop a secure by default JOSE library rather than to invent a new protocol, with a new format and new libraries? I can surely write some bad libraries for PASETO and someone could come up with the same arguments against PASETO like the OP.
PASETO is designed to be resilient against insecure implementation, just as its primitives were. You can do things to make stuff like Ed25519 unsafe (see, for example, a myriad of double-spend attacks), but they involve off-label use, which PASETO precludes.
By contrast, JWT was clearly not designed to be resilient against insecure implementation. A cryptographic engineer reading the spec would already have snorted milk through their nose at the sight of the "alg" header, the primitives included PKCSv15 RSA as a default _years_ after we knew it was unsafe, et cetera.
A strict JOSE might help, but I think it'll be ineffectual. There's little incentive to move ("we already audited this") and there's lots of incentive to stay because compatibility concerns reach further than security ("Cognito does this weird thing with base64 codas that is different from everyone else and we have to support Cognito"). Consider flipping it around as a thought experiment: if you were willing to give up compatibility, and you were going to integrate a new library anyway, why not go whole hog and do a protocol that was always safe?
Here's another thing I like about PASETO: because it's versioned, communicating about insecurities found further down the line is much easier.
With JWT you have to say stuff like "ensure that alg can't be 'none' and that your JWT library doesn't accept arbitrary alg fields". This is messy.
With PASETO you can just say "be sure to use v3 or later" (assuming someone finds a flaw in v2, files that issue, and that is then addressed in a v3 of the spec). Similarly, implementations can just write "supports versions 1 through 3" on their README.
In addition to versioning, we're starting with a very limited set of functionality tuned to security not flexibility.
If you're using v2, you're either signing with Ed25519 or encrypting with XChaCha20-Poly1305. There are no additional knobs or levers. Only boring cryptography.
A versioned JOSE that limited flexibility is dead in the water. JOSE users will bikeshed over backeards compatibility until the end of time. Might as well specify a new standard at that point. Hence PASETO.
Dynamic languages with no compile time checking of fields, assertions, etc. seem inherently very dangerous to me for anything security critical or cryptographic.
Sure you can write secure and correct code in them, but what happens years later when others (including yourself after you've forgotten what you wrote!) have come and made various edits, changes, refactors, etc.
This is generally where dynamic languages crash and burn, but it's particularly dangerous with stuff like authentication where a bug can be disastrous.
> Dynamic languages with no compile time checking of fields, assertions, etc. seem inherently very dangerous to me for anything security critical or cryptographic.
You don't seem to realize, but runtime checking and assertions is an equivalent thing, it's literally an empty claim. But dynamism actually allows more in terms of security, because you can track a lot of things at runtime implicitly and bail if anything doesn't satisfy some property. For example: taint checking https://en.wikipedia.org/wiki/Taint_checking
> Sure you can write secure and correct code in them, but what happens years later when others (including yourself after you've forgotten what you wrote!) have come and made various edits, changes, refactors, etc.
That's what test coverage is for. But your claims are wrong and ignorant either way. We have empirical evidence that less code means less bugs and that more expressive dynamic languages means less code for the same functionality and therefore less bugs too.
Can you cite any reason for this belief? All comparisons of dynamic languages vs statically-typed languages have found 0 or extremely minor effects on correctness.
He is saying dynamic languages crash and burn in this context. Specifying "dynamic" does strongly suggest non-dynamic languages do not crash and burn in this context.
Safer code can be written in C++ IF you take advantage of its type system to implement safety features, but the language doesn't force you to do this so there is much insecure C++ code around.
Go, Rust, Java, C#, Haskell, etc. are examples of relatively safe languages with type systems that mostly keep the foot guns in the foot gun cabinet.
The author does not just complain about JOSE and JWT but he also designed an alternative, PASETO: https://paseto.io/
Here's a nice PASETO write-up from Okta, a reputable third party: https://developer.okta.com/blog/2019/10/17/a-thorough-introd...
PASETO looks excellent to me, in that it's proper developer friendly and makes it hard for non crypto nerds like me to shoot themselves in the foot. I can't wait for it to replace JWT in popularity.