
Things to Use Instead of JSON Web Tokens - LaSombra
https://kev.inburke.com/kevin/things-to-use-instead-of-jwt/
======
Freak_NL
> The problem with JWT is the user gets to choose which algorithm to use.

Only if you completely bungle the implementation on the server-side. The
'none' 'algorithm' isn't supported by up-to-date JWT libraries with a good
track record, and you should always limit the algorithms you'll allow on the
server. So if you sign your tokens with a RSA-2048 key-pair, you would discard
any token that isn't using that algorithm.

Of course if you are building an API that blindly accepts whatever it receives
from a user agent you are bound to create a security gap — but that holds true
for anything users send you though, not just JWTs. JSON Web Token is not that
hard to grok, and it isn't a 'foot-gun' technology (just practice trigger
discipline — i.e., read the documentation).

I'm a Java guy, so I'll limit my experience to the libraries available there,
but of the four Java libraries available, three provide strict validation of
the signing algorithm out of the box, and explicitly document this in their
examples and documentation (I think the fourth does too, but I haven't tried
that one myself).

JSON Web Token is a neat standard that has a lot of good parts that can
reliably be used to create and process authentication tokens. So if you are
still worried about developers getting it wrong, then instead of saying 'don't
use JWT', why not promote a safe subset of the specification instead and
promote that? Call it 'iron-jwt' or something. It beats rolling your own
solution.

Or if you want to be particularly constructive and feel that developers are
misusing this technology, write a sensible, short, to the point implementers
guide for using JWT and spread the word.

~~~
JimDabell
> Only if you completely bungle the implementation on the server-side.

Which happens with regularity. This is exactly what led to the vulnerabilities
mentioned in the article.

This is a bit like arguing against the claim that generating SQL queries by
concatenating strings is unsafe. "Only if you completely bungle escaping the
parameters", right? As it turns out, that's an extremely common mistake. It's
easier to use a known-safe practice like parameterised queries than it is to
rely on developers avoiding this pitfall each and every time they have to
execute an SQL query.

Likewise with this. We know that negotiating the algorithm is subject to
mistakes, and it offers no benefits. So instead of relying on developers
avoiding this pitfall each time, let's avoid the pitfall altogether and get
rid of negotiation.

There's a human aspect to security that's being missed here. Saying what boils
down to "well developers shouldn't write insecure code" doesn't actually stop
developers from writing insecure code. You can point the finger after the
fact, but if you want to actually improve security, we need better standards
than this.

~~~
Freak_NL
> This is a bit like arguing against the claim that generating SQL queries by
> concatenating strings is unsafe. "Only if you completely bungle escaping the
> parameters", right?

No, you document how it should be done. Any major database layer using SQL
provides parametrised SQL queries, and strongly suggests developers use that
(usually in the quick start guide). You can still do your own concatenation,
but aren't advised to.

The JWT libraries that are up-to-date and well-documented don't recommend
blindly trusting the algorithm set in the header either, they recommend safe
approaches such as configuring your whitelist and letting any unlisted
algorithms fail. For example:

[https://github.com/auth0/java-jwt#verify-a-
token](https://github.com/auth0/java-jwt#verify-a-token)

Only if you completely refuse to read even the basic 'getting started'
documentation will you get to this kind of weird vulnerability. The issues
with this part of the JWT standard have been addressed by the libraries, what
remains is just a little bit of effort on the part of the developer — which
may be expected from someone writing security critical code.

That is, don't blame the hammer for the shoddy carpentry.

> So instead of relying on developers avoiding this pitfall each time, let's
> avoid the pitfall altogether and get rid of negotiation.

So write a concise pamphlet that can easily be shared with all of the JWT
libraries in an issue/bug report. If there is a good argument for having to
explicitly whitelist algorithms, they might welcome the suggestion.

Some libraries already do this mind!

~~~
kevinburke
I just documented how it should be done, in the article at the top of the
page. The answer is "don't use JWT." Use specific tools for the thing you are
actually trying to do, that have API's that are harder to mess up.

~~~
Minikloon
By that logic the answer is also "don't use SQL".

~~~
kevinburke
More like "Don't use SQL, if a thing adjacent to SQL exists that is better
suited to a particular use case, doesn't have a history of poor
implementations, and is harder for implementers and end users to screw up."

In this case:

\- crypto_auth, or HMAC-SHA256 by itself, for authentication

\- crypto_secretbox for symmetric encryption

\- crypto_box or TLS for public key encryption

~~~
deathanatos
Good JWT libraries essentially have a "box" and "unbox" function; the work
required by the client needed to go behind the library's back here is on the
same level as that needed to behind crypto_box's. Further, crypto_box works on
a lower level than JWT encode/decode functions typically do, and would leave
many concerns that JWTs handle _in the user 's hands_ for them to handle,
alone. Having the user write their own code to handle those concerns is a
terrible idea.

~~~
mmalone
I'm with you on this. I've never thought of JWTs as a session storage
mechanism; rather, I've always thought of them as a simpler (JSON-based)
alternative to technologies like X.509 attribute certificates and SAML
assertions. If you're creating a ticket / verifiable claim, there are a bunch
of security considerations that JWT at least lays the groundwork for, and that
NaCl secretbox doesn't appear to offer. Curious what OP thinks about putting
things like payload canonicalization, subject/issuer/audience specification,
and expiration entirely in the user's hands. I suppose its up to implementors
to do appropriate validation, but at least JWT simplifies the conversation a
bit.

------
jarym
Never read such nonsense masquerading as an authoritative piece of
information.

Author clearly doesn't appreciate that the ultimate truth of any
authentication scheme is you should not trust anything from the user. So what
if you take away a clients ability to specify what algorithm a piece of data
is signed or encrypted with - if you blindly just accept whatever a client did
and proceed then you're always gonna find yourself vulnerable.

Intel didn't use JWT tokens or pass a client header - they just trusted what
the client sent and landed themselves in the same mess. I make the point to
illustrate that what _real_ security pros do is make sure basic checks like
validating user input is done regardless of what specification or algorithm is
involved.

~~~
kevinburke
These points are covered in the article, and the library I wrote makes it
impossible to parse a token without performing verification with a secret key

~~~
jarym
Yes I read. However, you've failed to grasp a few things:

1\. The client should not get to 'choose' which algo it uses, it merely states
what algo it did use. Emphasis should be on the server to verify that the
client didn't do (or claim to do) something bad.

2\. What happens if in 5 years time the algo you've standardised on is
suddenly comprisable? You've ripped out the mechanism that updated clients
could theoretically use to signify that they're using a newer algorithm. Take
for example Git and its recent SHA collision issue.

3\. By emphasising that 'clients should not get to choose', you're making the
case that the choice is of itself a weakness it is not. The weakness is often
in how inputs are processed (and far more often than any weakness in
algorithms).

~~~
kevinburke
I point out numerous cases where the server made a mistake in verifying the
algorithm specified by the client. This is the point of reducing the
complexity of the interaction

If you are using JWT and someone breaks SHA2, you still have to worry about
downgrade attacks. To evade downgrade attacks, you'll have to detect the
protocol the client sends, and reject tokens that specify SHA2 or below. Or,
roughly the same position you'd be in with one good algorithm: still in need
of a backwards incompatible upgrade

~~~
politician
This concern was always supposed to be handled by algorithm whitelists. The
_intent_ was that services would consult a whitelist of algorithms before
accepting a particular JWT.

The idea was certainly not that services blindly accept any token from every
algorithm shipped in the library.

Your browser supports TLS 1.0, should you throw it out?

> If someone breaks SHA2...

JWT has a built-in mechanism for handling this: expirations.

~~~
kevinburke
There's no "better TLS" out there for shipping a tool that connects to
millions of different servers. There are many better options than JWT.

Unlike JWT, hundreds of the world's best security engineers at various browser
companies are working on mitigating the situation as well as possible.

~~~
politician
Indeed, however, consider that servers can and do limit which TLS versions and
cipher suites they accept.

------
ksri
I maintain a spreadsheet of the pros and cons of various authentication
techniques -
[https://docs.google.com/spreadsheets/d/1tAX5ZJzluilhoYKjra-u...](https://docs.google.com/spreadsheets/d/1tAX5ZJzluilhoYKjra-
uHbMCZraaQkqIHl3RIQ8mVkM/edit#gid=0)

JWT is extremely useful when you want a one-time use token to pass a claim to
another system. For example, employee portal generates a link for a user to
check their available leaves in the HR system. Since the user is logged in to
the employee portal, they shouldn't have to login to the HR system. JWT is
great for this use case. But for general sessions management, there are better
solutions.

~~~
vetinari
The use case you mention is exactly the reason, why we have SAML2 and similar
SSOs.

~~~
wichert
It appears to be much, much simpler to just integrate JWT into your system
than deploy a SAML identity provider. I would love to see an easy to deploy
decent SML IdP, but so far I have not found one. If anyone has any
recommendations I would love to hear them.

~~~
sytringy05
They dont exist! IMHO ADFS is actually the best of a bad lot. Your friendly
Windows Admin can setup the SSO in a matter of minutes without having to know
the spec inside out and upside down.

The other platforms I've used or integrated with - Tivoli, Layer 7, Ping
Federate, a huge hack job written in PHP - all took weeks/months to get
working.

That said I haven't tried Spring SAML recently, so maybe that is painless now.
But probably not

------
saganus
There's a lot of conversation on when should I use JWTs and when not to.

But as alternatives go, has anyone tried using Macaroons?

They've been mentioned in HN a few times but I've never seen the tech catch
up, even though it looks like a very cool way to implement authorization.

Is there any particular reason why?

Here are some resources I've found and I think Macaroons is a very interesting
concept. Even the paper is accessible to someone like me, without any real
security or cryptography expertise.

Research paper:
[https://research.google.com/pubs/pub41892.html](https://research.google.com/pubs/pub41892.html)

A new way to do authorization: [http://hackingdistributed.com/2014/05/21/my-
first-macaroon/](http://hackingdistributed.com/2014/05/21/my-first-macaroon/)

(This link has an invalid HTTPS certificate if that concerns you):
[https://evancordell.com/2015/09/27/macaroons-101-contextual-...](https://evancordell.com/2015/09/27/macaroons-101-contextual-
confinement.html)

After I found this, I've always wanted to try it out but haven't had the
chance. Does anyone has any experience or comments about it?

~~~
evancordell
You can use the http version until I get some time to setup letsencrypt (feel
free to disable javascript/css/etc).

I've used macaroons in several settings and highly recommend them. The only
thing really missing for "wider" adoption is something like a standard caveat
language, the lack of which keeps macaroon use pretty localized to your
specific deployment.

~~~
saganus
Thanks for the input!

I'm still hoping the tech catches up somehow and then there's probably going
to be more people interested in a standardized way to define a caveat.

When I was toying with Macaroons some time ago, I thought that I could use
JSON to format the caveat and toyed with the idea of defining a set of useful
caveats, but never got too far.

~~~
evancordell
It seems that most people have those thoughts when they play around with
Macaroons :) Check out the google group for some discussions:
[https://groups.google.com/forum/#!forum/macaroons](https://groups.google.com/forum/#!forum/macaroons)

If it wouldn't doom them to obscurity, I'd personally like to see a set of
vocabularies that macaroon users can use (a la semantic web). This is probably
as simple as namespacing caveats with globally unique identifiers to indicate
the vocabulary.

~~~
saganus
Yes, exactly! I actually did read the whole forum when I found out about them,
and that's where I got the idea actually. Not that I went much further than
what was discussed, but it definitely planted a seed on my mind...

Re: Vocabulary

Something like that sounds reasonable. I would just maybe add some sort of SET
operations logic that you could use to build more complex stuff.

Thus I would be able to delegate to someone a Macaroon that has admin access
to all of Project P EXCEPT (or MINUS) access to Project P's children in list
L. Or maybe delegate with access to any object in List (L1 AND L2). Sort of
like a SQL query (to an extent).

At least that was the use case I needed back then, i.e. How to secure an API
in a hierarchical way, such that certain user roles can access only certain
children of a certain parent node.

------
jondubois
Almost all of the 'alternative' use cases mentioned by the OP are not what JWT
was designed for. JWT was designed to authenticate users/entities by giving
them a token which contains basic non-sensitive metadata about that
user/entity. It's for authentication not for authorization.

Sure, some implementations of JWT have had bugs in the past, but this hasn't
been an issue for quite a while and it's definitely not an issue with the RFC
itself. It's the same as if you blamed the TLS/SSL RFC for being responsible
for the heartbleed bug in OpenSSL - It makes no sense.

>> You might have heard that you shouldn't be using JWT. That advice is
correct - you really shouldn't use it.

This type of blanket thinking is dangerous. There are cases where JWTs are
practically necessary and unavoidable. Whenever an extremist blanket idea like
this catches on in this industry, it becomes a major pain to have to explain
to people over and over why in THIS SPECIFIC CASE it is actually the best
solution possible.

~~~
Lukasa
> It's the same as if you blamed the TLS/SSL RFC for being responsible for the
> heartbleed bug in OpenSSL - It makes no sense.

It makes _some_ sense.

Features are attack surface. Each extra feature or option your protocol
enables is more code you need to manage. So careful decisions need to be made:
just because you can easily specify a feature for many use-cases in your
protocol doesn't mean you _should_ , because once you spec it people might
just use it.

For heartbleed, for example, why was the TLS Heartbeat extension ever
specified for TLS over reliable protocols? It serves no purpose: TCP has
TCP_KEEPALIVE if that's a thing you need. But it _was_ specified, and because
it was specified it was implemented, and then it became attack surface that
needed to be protected. It wasn't. So I guarantee to you that if RFC 6520 had
been more restricted in scope, the Heartbleed attack would not have happened
(or would have been a much more minor story, I can't remember if Heartbleed
affected only the TLS and not the DTLS implementation).

------
exabrial
I disagree with most of his points, but what really bothers me is the
underlying message of his article. I don't think we should fool ourselves into
thinking we can design a protocol that isn't susceptible to implementation
problems.

Did we get SSL/TLS right? No, we've failed a few times, but we're doing
better. Why is that? People are paying attention more that ever to OpenSSL and
now we have competition with LibreSSL and the like.

Side note: The irony of his coupler example; it's a flawed spec, not flawed
implementations... the implementations followed the spec but the spec was
dangerous from the start. JWT is the opposite: good spec, but a long time ago
some early adopters didn't get things right.

~~~
unscaled
I guess heartbleed gave everybody the wrong image, but most TLS
vulnerabilities were vulnerabilities _in the spec_. The fixes to RC4, BEAST,
SWEET32, POODLE, LOGJAM, CRIME, BREACH, BRICK, BORKED, BUSTED and whatever
else you could think of - all involved changing the spec. Sometimes by adding
mitigations, but mostly by banning TLS features.

TLS is a legacy protocol. Nobody likes it very much, but it's such an
established standard that you don't have much choice than trying to fix it.
The same might happen to JWT, but in both cases we'll be fixing the specs, not
just the implementations.

~~~
staticassertion
You could look at SMACK TLS as a few dozen examples of implementation specific
features due solely to the complexity of representing TLS state machines.
These aren't protocol weaknesses, they're weaknesses in the implementation due
to complexities in the protocol.

------
wvh
I've implemented some of OpenID Connect, "a simple identity layer on top of
the OAuth 2.0 protocol". Combined with OAuth 2.0, it's one of those giant
corporate specs (giant at least for security/crypto purposes) with way too
many options so anybody can do anything with any algorithm and any kind of
workflow.

I wanted to go with a simple, minimal NaCl-based system but in the end did
implement a lot of OpenID Connect in the hope it would make interoperability
easier with existing client libraries. I don't want to write a client for each
and every programming language other people in any related projects would want
to use. That in my opinion is the value of something like JWT: you can tell
people up front that that's the way they're going to get the user's ID data,
no matter how much server or client implementations will be switched around.

I feel that when faced with a spec like OpenID Connect and OAuth 2.0, it's not
necessary to implement more than what is strictly needed. If you don't need
all the flows and algorithms in your project, don't implement and don't accept
them. The parts you implement should comply – why base it on a spec if you
throw any interoperability out of the window – but don't waste months of
trying to correctly implement all of a huge corporate spec if that doesn't
make sense for the size of your project or organisation. Complete
implementations might have value only if that's your main product and you need
that line to sell it.

I use JWT only as ID, not as session, allow only one server-chosen algorithm
for signing, and rely on TLS for encryption.

There's clearly a need for up-to-date "web-approved" standards to pass crypto-
friendly data structures around – or maybe I'm just not familiar with any
recent efforts. Normalising and serialising JSON is pretty error prone...

------
luord
> implementation errors should lower your opinion of a specification. An error
> in one implementation means other implementations are more likely to contain
> the same or different errors. It implies that it's more difficult to
> correctly implement the spec.

Discussion on cryptography and particular implementations aside, I think this
is sound and I normally follow this when judging technologies.

------
tptacek
In cryptography, we have a concept of "misuse resistance". Misuse-resistant
cryptography is designed to make implementation failures harder, in
recognition of the fact that almost all cryptographic attacks, even the most
sophisticated of them, are caused by implementation flaws and not fundamental
breaks in crypto primitives. A good example of misuse-resistant cryptography
is NMR, nonce-misuse resistance, such as SIV or AEZ. Misuse-resistant crypto
is superior to crypto that isn't. For instance, a measure of misuse-resistance
is a large part of why cryptographers generally prefer Curve25519 over NIST
P-256.

So, as someone who does some work in crypto engineering, arguments about JWT
being problematic only if implementations are "bungled" or developers are
"incompetent" are sort of an obvious "tell" that the people behind those
arguments aren't really crypto people. In crypto, this debate is over.

I know a lot of crypto people who do not like JWT. I don't know one who does.
Here are some general JWT concerns:

* It's kitchen-sink complicated and designed without a single clear use case. The track record of cryptosystems with this property is very poor. Resilient cryptosystems tend to be simple and optimized for a specific use case.

* It's designed by a committee and, as far as anyone I know can tell, that committee doesn't include any serious cryptographers. I joked about this on Twitter after the last JWT disaster, saying that JWT's support for static-ephemeral P-curve ECDH was the cryptographic engineering equivalent of a "kick me" sign on the standard. You could look at JWT, see that it supported both RSA and P-curve ECDH, and immediately conclude that crypto experts hadn't had a guiding hand in the standard.

* Flaws in crypto protocols aren't exclusive to, but tend to occur mostly in, the joinery of the protocol. So crypto protocol designers are moving away from algorithm and "cipher suite" negotiation towards other mechanisms. Trevor Perrin's Noise framework is a great example: rather than negotiating, it defines a family of protocols and applications can adopt one or the other without committing themselves to supporting different ones dynamically. Not only does JWT do a form of negotiation, but it actually allows implementations to negotiate NO cryptography. That's a disqualifying own-goal.

* JWT's defaults are incoherent. For instance: non-replayability, one of the most basic questions to answer about a cryptographic token, is optional. Someone downthread made a weird comparison between JWT and Nacl (weird because Nacl is a library of primitives, not a protocol) based on forward-security. But for a token, replayability is a much more urgent concern.

* The protocol mixes metadata and application data in two different bag-of-attributes structures and generally does its best to maximize all the concerns you'd have doing cryptography with a format as malleable as JSON. Seemingly the only reason it does that is because it's "layered" on JOSE, leaving the impression that making a pretty lego diagram is more important to its designers than coming up with a simple, secure standard.

* It's 2017 and the standard still includes X.509, via JWK, which also includes indirected key lookups.

* The standard supports, and some implementations even default to, compressed plaintext. It feels like 2012 never happened for this project.

For almost every use I've seen in the real world, JWT is drastic overkill;
often it's just an gussied-up means of expressing a trivial bearer token, the
kind that could be expressed securely with virtually no risk of implementation
flaws simply by hexifying 20 bytes of urandom. For the rare instances that
actually benefit from public key cryptography, JWT makes a hard task even
harder. I don't believe anyone is ever better off using JWT. Avoid it.

~~~
politician
> For almost every use I've seen in the real world, JWT is drastic overkill;
> often it's just an gussied-up means of expressing a trivial bearer token.

This is certainly true for schemes that require trips to a source-of-truth
database to authorize a token (c->auth, c->resource, resource->auth). It's
also true for schemes where the token is associated with capabilities that are
loaded from a database. Using JWT to implement RBAC is flawed.

However, there is a strong use case for the token carrying its own
capabilities -- that is, a token that is more than just "20 bytes of urandom".

If a resource service can derive the capabilities associated with a token
generated by a trusted authentication service without contacting that service,
that has real world implications for lower latency, higher throughput
applications that are simpler to compose and operate.

As far the cryptographic credibility, the idea behind capability-based
security is an old one, and I'm sure you're aware of the research. This
particular spec may be problematic, folks may be misunderstanding and misusing
the primitives, but the underlying idea is sound.

Previous HN discussion of CapSec Wikipedia article
[https://news.ycombinator.com/item?id=10684129](https://news.ycombinator.com/item?id=10684129)

Google Fuscia
[https://en.wikipedia.org/wiki/Google_Fuchsia](https://en.wikipedia.org/wiki/Google_Fuchsia)

~~~
tptacek
I don't deny that capability tokens are useful; they certainly can be. JOSE is
just a poor vector for getting them.

The issue isn't with capabilities, or delegated authentication, or public key
tokens, or even standardizing any of those things. I think at this point I've
been pretty clear about what I believe the issues actually are.

~~~
politician
Thanks for clarifying; I'll reread your comments.

Do you have a standard that you would recommend for any of those things?

~~~
kevinburke
found in the article linked at the top of the page:

\- crypto_auth, or HMAC-SHA256 by itself, for authentication

\- crypto_secretbox for symmetric encryption

\- crypto_box or TLS for public key encryption

~~~
politician
I was asking about standards for Web-based capabilities, delegated
authentication, and public key tokens; not the individual message
authentication or (a)symmetric encryption components.

Echoing tptacek's comment above: the problems with using those individual
pieces is in the joinery - combining them in ways that are broken.

------
makomk
This complains that JWT does not have forward secrecy, and then recommends
NaCl's box primitive instead... which does not have forward secrecy either.
(This isn't exactly drawn attention to in the NaCl docs for some reason.)

------
komerdoor
I am using JWT for my projects to keep stateless sessions between servers and
for some other tokens (refresh, register, reset pass etc.). Of course extra
security measures are required (MitM protection [HTTPS etc.], XSS / CSFR
prevention etc.), but this has nothing to do with JWT. I use encryption with a
frequently rotated private key to encrypt the part of the payload that only
the server may read.

A good read at: [https://stormpath.com/blog/where-to-store-your-jwts-
cookies-...](https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-
html5-web-storage)

~~~
unscaled
The problems with JWT are not related to MITM, XSS or CSRF vulnerabilities.
You'll have to address these issues regardless of the type of token you're
using.

The problems with JWT can be divided into two classes: 1\. Too many options,
making it easy to misuse. Even if you disallow the 'none' algorithm (like most
newer JWT libraries), there are still many other ways to break it. e.g.:
[https://auth0.com/blog/critical-vulnerabilities-in-json-
web-...](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-
libraries/)

2\. Misguided cipher choice. AES-GCM (easy target for nonce-reuse), RSA, NIST
P-curves.

So in short, even if you're using encryption, JWT just makes it easy for the
crypto itself to fail.

~~~
komerdoor
I agree. Thank you for pointing that out. That is why I restricted my JWT code
to only accept / use certain options. Of course I could still have chosen the
wrong cipher for my specific use case and am aware that JWT will not solve
this for me.

What JWT is doing is actually not that special as it is just a standardized
container (akin to MKV and supported codecs) inside which existing
technologies can be used. Easy to write something similar if you know what you
are doing. I did that before, but still missed some extra verifications
already build into JWT.

Of course, the chosen technologies allowed to be used inside a JWT can still
be prone to vulnerabilities. I am not sure if that can be blamed on JWT.
People should still think about which options to use.

------
ath0
This is a case where the high-level point - "insecure options shouldn't be
configurable" \- conflicts with a reality of crypto protocols: you have to
make tradeoffs based on the best known attacks and the platform you're running
on, and those change over time. The best hashing algorithm, HMAC algorithm,
and signing algorithm to use on a mobile device in 2007 isn't the same as the
ones you'd pick today. Any protocol expected to last 10 years should allow for
the selection of an underlying crypto algorithm. Maybe "none" should never
have been an option - but tying the algorithm to the protocol has pretty
severe drawbacks, too.

More broadly - JWT isn't just about the exchange between a single client and a
server; the choice of "use cases" misses a very real constraint of multi-party
protocols. Within the context of OpenID (or OAuth more broadly), it's about
the relationship between an end-user, a resource owner, a client and an
authorization server -- all of whom need to be able to interact with a token,
and often offline.

~~~
tptacek
This is in fact not true: an HMAC-based design from 2007, even one that used
SHA-1, would remain sound today. HMAC hasn't changed in something like 20
years, and works even with MD5 (we've had since the 90s to make the migration
from MD5 and I obviously don't recommend anyone continue using it).

To non-cryptographers, this idea that protocols need to be constantly ready to
accept new ciphers in case there's a break in one of the old ones is a very
big deal, so much so that every amateur crypto protocol design includes cipher
suite negotiation as the centerpiece of the protocol. In reality, it's a minor
concern. Which the exception of RC4, pretty much every TLS ciphersuite flaw
has been the product of flawed joinery and not problems with underlying
ciphers --- which is why the major breaches have forced us to move people not
from one ciphersuite to another, but instead from SSL3 to TLS 1.0 to TLS 1.1.

For an expert design example, look at Trevor Perrin's Noise framework. An even
simpler idea: simply specify a single set of coherent cryptographic
constructions, and then version the whole protocol --- if there's a serious
break in your protocol, you'll almost certainly have to make changes across
the protocol anyways --- and upgrade the whole thing.

------
ceejay
I was just thinking. What is a good way to phrase the problem in order to
understand whether there are more pros / cons to having the client vs server
decide which algorithms to use in a transaction.

I haven't thought this through fully, but as far as I can tell ecosystems on
the web evolve. And so I think it's probably a good idea that we architect
things for the web in such a way that we don't inhibit that evolution. When
you put a decision like encryption algorithm in the client's hands does it
feel to anyone else that the security will evolve more rapidly, and thus
remain more robust? When the client is deciding, there's a larger pool of
people "voting" for what is an acceptable level of security. Even though a lot
of those "votes" will be based on the default settings of a library, that
library will over time become less popular as more and more people consider it
unsafe.

By the same token, if a particular service (server-side) does not keep up with
that evolution, fewer and fewer people will use it as other (safer) services
pop up.

------
tscs37
It doesn't seem like the author is actually proposing an alternative, rather,
the only thing says is "Don't use JWT, here is how you can do X with Nacl"

Even worse;

It is suggested that to authenticate a user one should use TLS. That might be
true for a login form, but not beyond that. Once you have logged the user in,
you need to continue authentication on every request. JWTs are one way to put
this information on the client side without having to put any much trust into
it.

The second example is a simple asymmetric encryption example which... for some
reason JWT is not a solution for? I've used Ed25519 plenty of times with JWT
(custom algo header in this case), so I see no problem there plus... I don't
think this is what JWT is actually trying to solve.

The third example is encrypted data to the client, which is also something JWT
isn't trying to solve, this is what JWE is for. JWT is purposefully
unencrypted and I'm not sure how many developers would actually pretend a
signature is encryption.

The last part is an actual example of JWT use cases, in which case however the
author blabs on about the (in)famous "algo=none" bug a lot of libraries had.
I've specifically used the Go library mentioned and strictly enforcing the
algo is a nonbrainer if you are using a custom one anyway. On the other hand,
I still use HMAC for a seperate token for short-term authentication over
endpoints (to make blacklisting logins easier).

So JWT simply gives me some flexibility in sharing common code for
authentication, the same code can consume the long-term tokens and the short-
term tokens and much more if needed in the future.

I'm not saying JWT is the end all for problems, but it's rather easy ready-to-
use solution for some of my problems.

Why write a signature library when there is one ready to use that, with care,
is safe to use?

~~~
kevinburke
I address these points in the article

------
10165
"..."algorithm agility" that is a _proud_ part of the specification" (italics
mine)

No idea about "JWT" but maybe this is part of the psychology that keeps
schemes like SSL/TLS in use. (Part.)

Do you think there are people who are actually _proud_ of achieving complexity
in a specification or implementation?

------
deathanatos
> _But the server and the client should support only a single algorithm,
> probably HMAC with SHA-256, and reject all of the others._

If you have a centralized system dealing w/ authentication, this doesn't work,
as now everything that needs to verify JWTs needs the secret. The support for
RSA, instead of HMAC, is there to meet a different set of requirement.

What people fail to remember is that JWTs — and the libraries that work w/
them — do not just wrap data to be authenticated. They also handle verifying
the various claims on a token — is this token applicable here? is this token
expired? — things relevant to an authentication token, not just a mere signed
blob of data. The suggestion to leave those to be reimplemented by every
single end-user is bad advice.

~~~
kevinburke
Maybe not a great time to mention I also found errors in the claims
verification in the one library I tested, and ended up ripping that code out
as well

------
palmdeezy
What makes this all worse is that companies like Auth0 and Stormpath have
flooded search results with self promoting blog posts masked as tutorials.
This just makes it harder for developers to learn the basics without getting
product shoved in their face.

~~~
dmix
I don't see a problem with companies writing tutorials and OSS libraries to
share with the community. If there is an economic incentive for documentation
to be written and free software to be created then what's the problem really?

If the article is blatant self-promotion then I could see the problem with
that and those articles don't get anywhere on HN/Reddit/etc so they won't rank
well on Google either. But I've seen some high quality docs/libraries coming
out of companies like that and it's a great thing.

The aren't responsible for developers doing poor implementations of JWT. And
other developers equally have a voice such as the OP if they have a problem
with the choice of technology they are promoting.

------
ZoneGhost
For the record, JWT is a payload and format spec for JWS/JOSE, which is really
what you're complaining about. JWT is merely a claims set and an optional dot-
notation serialization of a single signature.

JWT/JWS libraries that handle all the validation alone are treacherous. You
should ALWAYS parse the JSON before hand, perform your claims and header(s)
validation, and then pass the payload/header/signature. If anything, it's
computationally less risky than running the signature blindly through a
signature validation function and then checking the header.

~~~
kevinburke
you could also choose to use safer libraries and cryptographic primitives

~~~
ZoneGhost
There's nothing a library can add to make things "safer" when it comes to
application-specific constraints. If I'm checking to make sure I only accept a
specific algorithm, I'm not going to blame a crypto library for validating
something that is technically accurate (short of maybe disabling the "none"
algorithm by default). You should also be in possession of at least the public
key beforehand, and rely on that for authentication, rather than anything in
the claim.

------
tracker1
The implementations of JWT that I've mostly used... internal signing and
validation only... the algorithm and public key are pretty much pinned down.
If you do that, JWT is a pretty valid format... it's when you leave things
open to "whatever" that the security issues come through.

I don't have a problem with JWT, only in that having the signature method, etc
configurable in the first place as an implementation detail is probably a bad
idea.

------
ceejay
If the specification requires the server to decide which algorithm to use a
naive client, who doesn't know which algorithms are safe or not, is just as
dangerous.

As far as I know there are no algorithms that exist today that we can
guarantee will never be broken in the future. So algorithm choice inherently
must be decoupled from the specification.

EDIT: Or a naive server implementation for that matter...

------
arrty88
Are there any examples of big JWT hacks which took place due to a
vulnerability

------
unscaled
Good writeup of what you should be careful with with regards to JWT. There are
some inaccuracies there too. First of all, JWT doesn't support encryption at
all - it's JWE that does that. It's an important distinction, since most JWT
libraries I ran into don't feature encryption, so if you want encrypted tokens
you'll need to use an extra JWE library, or a more full-featured JOSE library.

JWE also support more than just RSA - it definitely does support Elliptic
Curve Cryptography (although I would prefer if they chose Curve25519 instead
of the NIST curves), and they are used with EC Diffie-Helman in a certain
construction that actually gives you _more_ forward secrecy than NaCl box.
NaCl Box offers you no forward secrecy, whereas all the ECDH-ES algorithms in
JWE offer you partial forward secrecy, which saves you when the sender key is
leaked, but not when the receiver key is leaked. That's the best you can get:
we can't have a two-way perfect forward secrecy in non-interactive protocol
like JWT since we can't perform a direct negotiation of ephemeral keys between
sender and receiver). Of course, we're actually comparing apples to oranges
here: you can get the same partial forward secrecy guarantee with libsodium's
sealed box (not in the original NaCl):
[https://download.libsodium.org/doc/public-
key_cryptography/s...](https://download.libsodium.org/doc/public-
key_cryptography/sealed_boxes.html)

As for an alternative to JWT/JWE, I think it really depends on what people
want, but I have slightly different suggestions:

1\. For simple access tokens in low-medium load scenarios, access tokens
stored in Redis are probably simpler to implement than JWT + revocation.

2\. If you don't have any secret information inside the token, HMAC-SHA256.

3\. If you have secret information, I'll actually go with libsodium's
XChacha20-Poly1305 AEAD: [https://download.libsodium.org/doc/secret-
key_cryptography/x...](https://download.libsodium.org/doc/secret-
key_cryptography/xchacha20-poly1305_construction.html) secretbox doesn't
support AEAD, but you often have external data that you want to tie the token.
It's very easy to implement exactly the same construct with XSalsa20, so it
will really be just secretbox with AEAD support, but that's non-standard and
you won't find any native library support.

4\. Public signature of public data with Ed25519 (this is NaCl's crypto_sign).

5\. Authenticated asymmetrically encrypted tokens: to get partial forward
secrecy, the easiest way would be using sealedbox and then signing the result
with crypto_sign. It's not the most efficient way to do this, but
NaCl/libsodium don't have a tailored operation for this use-case, so you would
have to use primitives directly.

All in all, not quite clear cut, and nobody is making a library that does that
for you, so it's easy to see where JOSE is coming from.

------
pmarreck
He should release "JWT-H2O" i.e. JWT with HMAC 256 Only. :) (left a similar
comment on his blog)

------
Gonzih
One should always validate algorithm before doing anything with JWT on the
server side.

------
retrogradeorbit
This is acronym heavy. Author needs to specify in the opening which JWT he is
talking about. Java Web Toolkit? or JSON web token? It took me a fair amount
of reading to work out which one he means. And even them I'm only pretty sure
he means JSON web token, but I can't be sure because the Java Web Toolkit also
connects to servers, and uses encryption, and all the other stuff he talks
about.

~~~
gant
People still use Java Web Toolkit?

Okay, dumb jokes aside, they're clearly talking about alternative ways to
authenticate, so I wouldn't know how you could conclude this was about
anything but JSON Web Tokens.

~~~
retrogradeorbit
People still use Cobol, mate.

Just specify in the first sentence what you are talking about as full words.
Is it that hard? Apparently it is.

~~~
coldtea
> _People still use Cobol, mate._

Which makes sense. It has been a historically succesful language that served
well for decades.

JWT wasn't even good when it was new.

------
jlebrech
sessionstore and give your client a cookie.

------
jlebrech
JWT is just storing more info than you would with a cookie but pretending it's
secure by encrypting it with an algorithm the browser has access to.

~~~
rhinoceraptor
JWT are not encrypted, they include an HMAC signature to prove that the token
claims (which are a Base64 encoded JSON object) have not been modified.

~~~
alayne
JWT can be encrypted.
[https://tools.ietf.org/html/rfc7519#page-26](https://tools.ietf.org/html/rfc7519#page-26)

------
gant
Oh hey, it's another "JWT libraries used to be terrible" article.

Idiots shouldn't write authentication code. Especially when credentials are
involved.

Funny jwt-go was used as an example; it was never vulnerable to the alg-none
attack: [https://github.com/dgrijalva/jwt-
go/commit/2b0327edf60cd8e04...](https://github.com/dgrijalva/jwt-
go/commit/2b0327edf60cd8e04d7ee6670b165c9580a42392)

~~~
developer2
>> it's another "JWT libraries used to be terrible" article

Dead on. Sure, some early JWT implementations were poor... during the first
few months that JWT was gaining traction. That was over 2 years ago. You may
as well write an article about how Internet Explorer is awful, while referring
to qualities present in IE 6. Disclaimer: I still dislike IE/Edge, but no
longer have pertinent reasons as to why I maintain that opinion.

There is not a single valid criticism of JWT from a security perspective. The
only criticism outside of security considerations I'd view as valid is that
the length of the strings quickly becomes bloated for the amount of
information contained within (ie: inefficient bandwidth and storage usage, the
same complaint as with long cookie headers requiring more TCP packets).

~~~
kevinburke
Usability and implementation errors are security errors

[http://blogs.adobe.com/security/2017/03/critical-
vulnerabili...](http://blogs.adobe.com/security/2017/03/critical-
vulnerability-uncovered-in-json-encryption.html)

see the "X.509" section here
[https://www.npmjs.com/package/jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken)

[https://twitter.com/bcrypt/status/583070541336195072](https://twitter.com/bcrypt/status/583070541336195072)

------
cheerioty
Huh? The alternatives listed make me wonder if the author actually knows what
JWT is being used for.

------
sergior
hey, author is missing the bit where you can disallow client to choose the
algorithm. No need to read the rest...

~~~
mrighele
In some way he addresses that towards the end:

> It's important to note that my experiment is not JWT.

> When you reduce JWT to a thing that is secure,

> you give up the "algorithm agility" that is a proud part

> of the specification.

I don't agree with him though, unless the standard requires to implement all
of the available algorithms, one may choose to implement only those that
he/she deems safe/worth.

~~~
theprotocol
>I don't agree with him though, unless the standard requires to implement all
of the available algorithms, one may choose to implement only those that
he/she deems safe/worth.

Agreed. I view this flexibility as a developer feature, not a client feature.

~~~
kobeya
Correct. Let's say you implement RSA2048 and server-side reject all other
algorithms. Then during a security audit the crypto guy points out that
RSA2048, while not broken per se, is not up to the generally-accepted 128-bit
security threshold. You should use RSA-3078+ or switch to ECDSA. You decide to
switch to ECDSA for the space savings. But what about all the deployed
clients? Well since it's not actually broken, you continue to accept RSA-2048
for the next couple of years until something else permanently breaks support
for old clients. Supporting client-specified algorithms lets you do a safe,
phased-in upgrade without breaking compatibility or any fancy engineering.

------
qatanah
One of the advantages in using JWT is that the verification is in the cpu
level and not a lookup via disk. This may sound strange, but if you don't have
a quick lookup cache or centralized cache, This would be a great advantage to
use CPU.

~~~
kevinburke
This is not a cryptographically sound argument

------
yellowapple
So we should stop using cell phones because one implementation happened to
spontaneously combust. Got it.

Or maybe - just maybe - the claim that specifications should be judged by
their implementations is entirely nonsensical. The fact that Internet Explorer
exists doesn't in and of itself mean that web browsing as a whole is a
defective concept. The fact that single-ply toilet paper exists doesn't mean
we should stop using toilet paper. Likewise, the fact that some JWT
implementations are defective does not in and of itself say a whole lot about
JWT itself.

