16 ms·
The criticisms of JWT seem to fall into two categories: (1) Criticizing vulnerabilities in particular JWT libraries, as in this article. (2) Generally critici
by StevePerkins 10y ago
The criticisms of JWT seem to fall into two categories:
(1) Criticizing vulnerabilities in particular JWT libraries, as in this article.
(2) Generally criticizing the practice of using any "stateless" client tokens. Because there's no great way to revoke them early while remaining stateless, etc.
The problem is that both of these groups only criticize, neither of them can ever seem to actually recommend any alternatives.
I could care less about JWT per se. I'm happy to implement a similar pattern with something else (e.g. store a secure cookie post-auth, skip all the refresh business and just let it expire when it expires, and employ an ugly revocation strategy only if absolutely necessary). I don't need JWT for this.
If I'm providing a REST API, then I'd prefer a token string that I could pass as a header value rather than forcing the use of cookies. Although I suppose you could argue that a cookie is just another header value.
Either way, if you're serving up a REST API to a JavaScript UI... what's NOT a good option is server-side session state (e.g. Java servlet sessions). That requires you to either: configure your load balancer for sticky-sessions, or employ a solution to share session state across all your server-side instances (which never works very reliably). Moreover, relying on a session isn't a very RESTful auth strategy in the first place.
So if I'm writing a SPA in 2017, then I'm definitely taking a client-side approach and running afoul of the #2 critics. And since JWT is so widely implemented (e.g. if I use a "Login with Google" option then I'm using JWT), I'm probably running afoul of the #1 critics too.
These criticism are fine, I guess. There's no faster route to blog clicks, book sales, speaker invites, and consulting dollars than: (1) telling everyone to jump on this year's hype train, or (2) telling everyone that last year's hype train sucks. What the world really needs is a bit more actual prescriptive recommendations of what to do instead.
- tptacek 10y agoI don't care if you want to use stateless client tokens. They're fine. You should understand the operational limitations (they may keep you up late on a Friday scrambling to deploy a token blacklist), but, we're all adults here, and you can make your own decisions about that. The issue with JWT in particular is that it doesn't bring anything to the table, but comes with a whole lot of terrifying complexity. Worse, you as a developer won't see that complexity: JWT looks like a simple token with a magic cryptographically-protected bag-of-attributes interface. The problems are all behind the scenes. For most applications, the technical problems JWT solves are not especially complicated. Parseable bearer tokens are something Rails has been able to generate for close to a decade using ActiveSupport::MessageEncryptor. AS::ME is substantially safer than JWT, but people are swapping it out of applications in favor of JWT. Someone needs to write the blog post about how to provide bag-of-attributes secure bearer tokens in all the major programming environments. Someone else needs to get to work standardizing one of those formats as an alternative to JWT so that there's a simple answer to "if not JWT then what?" that rebuts the (I think sort of silly) presumption that whatever an app uses needs to be RFC standardized. But there's a reason crypto people hate the JWT/JOSE/JWE standards. You should avoid them. They're in the news again because someone noticed that one of the public key constructions (ECDHE-ES) is terribly insecure. I think it's literally the case that no cryptographer bothered to point this out before because they all assumed people knew JWT was a tire fire.
- asanso 10y agoIt seems that Matthew Green warned them about some of their choices though back in 2012!! https://www.ietf.org/mail-archive/web/jose/current/msg00366.html https://www.ietf.org/mail-archive/web/jose/current/msg00366....
- fovc 10y agoIt's not that need an RFC standardized solution for everything, but I'd rather not roll my own anything related to crypto. Would something like crypto_auth(json(bag)) be better here? (crypto_auth from libsodium, json being sorted without whitespace)
- tptacek 10y agoYes, that would be much better, and it's what I mean when I say that JWT doesn't bring anything to the table.
- arethuza 10y ago"json being sorted without whitespace" What is the significance of that part?
- zeveb 10y agoIt makes JSON deterministic, which it isn't by default (e.g. {"foo": 1, "bar": 2} and {"bar":2,"foo":1} are both valid serialisations. Of course, it'd be better still to use a format _meant_ to provide human-readable canonical representations of data, e.g. Ron Rivest's canonical S-expressions (http://people.csail.mit.edu/rivest/Sexp.txt http://people.csail.mit.edu/rivest/Sexp.txt), but of course this is information technology and we have to reinvent the wheel — usually as an irregular polygon — every 3-4 years rather than using techniques which are tried and true.
- arethuza 10y agoAh yes, similar to canonicalization of XML for XMLSignature? Presumably this means that you have to have have a "flat" JSON structure rather than lots of nested objects and arrays?
- lr4444lr 10y agoEither way, if you're serving up a REST API to a JavaScript UI... what's NOT a good option is server-side session state (e.g. Java servlet sessions) Can you explain what you mean, as oppose to other kinds of session tokens? Roy Fielding makes it abundantly clear[0] in the seminal delineation of REST that We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. This has given me pause to doubt just how many people are really implementing REST, and/or how useful a model it is in modern web applications. [0]https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arc...
- meric 10y agoIMO sessions for authentication is fine as long as we don't store any session variables. In the end someone's going to be keeping track of the number of GET requests made by each API consumer on each endpoint, and practically it's not breaking REST as long as that state doesn't affect the information GETable by the client.
- lr4444lr 10y agoI just can't reconcile the fact that if I hit an endpoint, and I get back certain data with a 2XX response code because I previously accessed a "login" resource, but I would have gotten a 4XX response code if I had not gone to that prior "login" resource that I haven't violated REST: my request for the second endpoint takes advantage of stored context on the server. Even worse, if I restart the server, change out its database, or make some other stateful change on it, the response changes. And I don't mean to imply that this is a universal sin of computing architecture, but it sure as hell looks like a violation of REST, and it begs the question of what our standard is. Headers, path-based nomenclature, network layering, authentication - I'm on board with all of that. I just worry that a lot of people might be falling victim to commonplace misconceptions of just what REST is, which in turn may be causing us (the web dev community) to make misplaced value judgments.
- lobo_tuerto 10y agoI found this video incredibly informative about how to effectively implement JWTs, along with security advice and a nice refresh-reissue process: https://youtu.be/mecILj3p4VA?t=2m8s https://youtu.be/mecILj3p4VA?t=2m8s
- meddlepal 10y agoI feel like the argument against #2 is usually purely hypothetical in nature. I really do not have a problem maintaining a small lookup cache for revocations. I feel like the argument against doing this tries to take the form of all server-side kept state is bad when in reality it's sticky state and huge object graphs (read: memory consumption) that get stuffed into session objects that are the real evil. A server with 1GB can hold a lot of JWT's in memory. Probably more than most of the people building services here have to actually deal with.
- falcolas 10y agoSure, revocation lists are relatively small. But they need to be available to every server (replication), be proof against server/service restarts (durable), and checked with every request (highly performant). So, a good revocation list effectively requires a database. Not a trivial thing to implement yourself, and a weighty requirement for an otherwise stateless service.
- justinclift 10y agoHmmm, using a database (eg PG) for the authoritative information, with memcached in front sounds like it would be practical for most uses.
- falcolas 10y agoAt which point you should probably ask yourself: "What value is keeping all of my state inside this token providing me?"
- mwpmaybe 10y agoProbably not. If the Pg instance is replicated, as indicated above, it'll be challenging to keep the Memcached copy in sync. In other words, you can't just use the caching feature of your ORM, you'll need another piece.
- justinclift 10y ago
- gregpardo 10y agoFor number 2, you could expire them by encoding some identifier based off a hash or key tied to the user object. Change that object and have the server reject the token if that meta data no longer validates.
- tracker1 10y agoOr have really short lived tokens, requiring regular refresh, and don't worry about expiring them... you can then delete the refresh token so it can't be found requiring full re-auth if necessary. OAuth2 + JWT is fine... just whitelist the algorithms you allow and use HTTPS for all communications, even internal.
- mgkimsal 10y ago> If I'm providing a REST API, then I'd prefer a token string that I could pass as a header value rather than forcing the use of cookies Aren't cookies just strings passed as HTTP headers?
- meric 10y agoI hope someone can explain to me in practical terms difference between a session cookie string on a request and a token as header value.
- Illniyar 10y agoCookies are just string in a header. The difference is that unlike normal headers browesers treat cookie headers in a special way. They automatically add and remove keys from it, and they allow the server to set the header in a way that the client can neither see it nor change it (http only headers)
- zeveb 10y agoOne small correction: the client (i.e., the web browser or other web client) can see HTTP-only cookies just fine; code running in a conforming browser cannot. But if I write some code using DRAKMA, urllib or net/http, and can see those cookies just fine.
- deathanatos 10y agoThe downside being that the browser will attach it to every request; if you use cookies, you MUST be aware of this, or you are (IMO) pretty much guaranteed to write a CSRF vuln. (I'm much more in the localStorage + Authorization header for this reason. I recommend [1] for reading. If malicious JS is running, cookies won't save you, since the malicious JS is capable of simply making the request itself, to which the cookie will automatically be attached by the browser. localStorage+JS eliminates CSRF. If someone XSS's you, the difference is irrelevant.) [1]: http://blog.portswigger.net/2016/05/web-storage-lesser-evil-for-session.html http://blog.portswigger.net/2016/05/web-storage-lesser-evil-...
- tboyd47 10y agoThe article very clearly is about the standard, not a particular JWT library. Server-side session tokens stored in the database worked fine ten years ago, and they work fine today. No need to muck with the load balancer. Stateless tokens are great too, and use two-factor auth when you need that extra layer of security. No need for newfangled standards; HTTP Basic remains a simple and effective way to convey that token.
- tracker1 10y agoExcept there are now many instances where no single database server can keep up with request load. It's not fine in all cases today. Where I work now a single request from the user goes into a pipeline of requests (some can be parallel, others not)... our SLA is X, everything that adds up to the total request time counts. Adding even 2-3ms for each service layer to verify session keys is too much. This is as opposed to < 0.1ms for verifying a JWT. JWT is a structure for stateless tokens... once you have a token, what does 2FA add? nothing. Also, some algorithms are insecure, so don't use them, or blacklist them... Or, better whitelist the algorithm you do use.
- tboyd47 10y agoI've got nothing against stateless tokens. What I'm saying is that it can be a much easier and more effective pattern to add a second layer of security than to add complexity to the first layer (the token). I believe this is like the idea of defense in depth. For example, making signed-in users re-enter their password before performing certain actions may be preferable to introducing cryptography into all sign-in actions.
- tracker1 10y agoThis isn't just for all sign-in actions.. it's for all API requests, and in some designs passthrough requests on behalf of a user to another server/service. It isn't just used for UI requests. It can also be used from Server to Server/Service requests... across data centers. You can do signed tokens/authentications without introducing many potential points of failure.
- jchw 10y agoWhat's difficult about setting up a Redis cluster to back sessions? Yes, it adds a point of failure... so does having a database of any kind. However, I'd hardly call it difficult. If you're on Amazon, you can just create an Elasticache cluster and not even concern yourself with the ops. I don't hate secure cookies or anything, but some people act like plain-old regular cookies haven't been thoroughly solved by this point. Related: Something people get wrong a lot with secure cookies is worrying about obscuring the cookie more than securing it. Encryption does not give you authentication; you need MAC for that. An encrypted message can still be blindly modified. Imagine being able to change a UID stored in a "secure" cookie even if you couldn't 100% control which. Eventually, if you try enough permutations, you're going to escalate your privileges!
- jdmichal 10y agoNothing's difficult about that. But that doesn't mean that it's a good idea. How about distributing a signature and encryption key to all your servers, and using them to secure the outgoing and verify the incoming tokens. If you want easy, that's probably even easier than setting up a Redis store and tying your services to it. Need an emergency revoke of every token? Easy: Replace your signature key. Any older token will fail signature verification. In which case, your system should require authentication and then generate a new token with an updated signature.
- chmike 10y agoWhen the authentication info needs to be used with servers in different location of the world, JWT is better. Getting the session info from a redis server or something equivalent isn't free. Deciphering a JWT token may be faster. So, the most appropriate method depends on the use case. If all the servers are in one location, a random byte sequence as session id key with cached info is the most simple, compact and efficient.
- jjawssd 10y agoOr you can use read only Redis replication and keep your architecture pretty much the same https://redis.io/topics/replication https://redis.io/topics/replication
- jv22222 10y agoOn another note. Dear Americans, the queen would like you to stop saying "could care less" - by David Mitchell of Peep Show https://www.youtube.com/watch?v=om7O0MFkmpw https://www.youtube.com/watch?v=om7O0MFkmpw
- nocman 10y agoI am American, and I'm sure this bothers me more than it actually bothers the queen. Between that and the incessant use of the incorrect phrase "for free" instead of the correct phrase "for nothing" it's amazing that I can stand to read anything on the internet. xD
- eric_the_read 10y agoI could care less about this request, but I can't be bothered to make the effort.
- jdmichal 10y agoI can make an attempt at an alternative: Distribute signing and encryption keys to all servers. Have them encrypt and sign the outgoing serialized token, whatever that consists of. Have them verify and decrypt the incoming token. This is just straight-forward cryptography, with keys known only to the server, so I'm pretty sure you won't get any arguments from (1). (And, I suppose the encryption could even be skipped, if you don't care that the internal format of the token is known.) Emergency revocation of all tokens [0] is simply rotating the signing key. All tokens issued prior to the rotation will fail verification with the new key. That should trigger the authentication process, which will issue a new token with the updated key. This solves the revocation issue present in argument (2). [0] Any other form of revocation is, in my opinion, not distinguishable from having server-side state. If you have to keep a list of bad tokens, why not just keep a list of the good tokens instead... And then it's only a short hop to the token being nothing but a key to lookup the full session state on the server.
- deepanchor 10y agoThis is exactly the solution I use. I use a secret server (Vault, using Consul as a backend) to securely distribute and manage the encryption keys.
- batoure 10y agoYou do understand that this is fundamentally the exact underlying mechanic of JWT?
- jdmichal 10y agoYou call it the underlying mechanic. I call it the only necessary mechanic. If those additional mechanics are where the security issues come from, then just get rid of them.
- tracker1 10y agoNo one is forcing you to accept/implement ALL possible aspects of JWT.. in fact, that's generally a bad idea... Only need to implement what you need. If a specific algorithm is bad, don't allow it... Isn't this how HTTPS works, HTTPS today doesn't use the same SSL and algorithms allowed in 1996, it's evolved and changed in practice. The author isn't suggesting everyone just not use HTTPS because some possible algorithm has been determined to be weak is he?
- batoure 10y agoI grow more and more tired of posts touting engineering sensationalism. Here is a point of order for developers who work on something realize it isn't idiot proof (them proof) out of the box and then want to write a sensational post: Implementation and design are a core part of anything you do and considering the risks and accounting for them are part of doing business. Having worked with large organizations that do active and passive scanning of the web I am constantly shocked how often we are contacting someone about basic SQL injection in their application... in 2017. JWT is an incredibly powerful standard if implemented effectively but its not for the LAZY, it requires thoughtfulness where ever it is active. JWT solves a serious and real problem that organizations face at scale which is why you see it implemented in systems like google sign in. Realistically its not going anywhere. People love criticizing the movement towards stateless tokens on the web I find it pretty funny... crawl down the stack from their webheads and you usually come face to face with Kerberos managing auth within their networks...
- CiPHPerCoder 10y ago> (1) Criticizing vulnerabilities in particular JWT libraries, as in this article. The purpose of this article it criticize the standard, not particular libraries.