Pros and cons in using JWT (JSON Web Tokens)
For apps that require a sever-side implementation, the clients (mobile app or web browser) generally have to prove their identity to the server. A user using Chrome to open Facebook.com (FB) that he was previously logged into sends some data to the FB server proving his identity.
This is necessary, as HTTP calls (and even initial Websocket Connects) are stateless. Up until recently, it was done using Server Side Sessions that are stored in the DB. Now, a new standard called JWT has emerged and is being used by quite a few systems.
Here we compare traditional Sessions vs JWT.
My comparison will be biased towards Sessions, as JWT is relatively new for me and I have exploited the sessions for my architectures that cannot be used along with JWT . Also, I am a bit of security freak and JWT has its drawbacks.
How each works
In both cases, once the user is authenticated for the first time, the server sends a seemingly random string to the client, which the client stores in persistent storage (e.g. web storage, cookies, NSUserDefaults) and with every subsequent request, it will send the string that is used to identify the user-id on the server.
Session: This generally involves a DB table that has all of the session tokens mapped to the user-id. The Session token string is generated randomly. Whenever the user queries, e.g., Self Profile, the server fetches the user-id from the table and returns the profile from a profile table.
Any other details like device-type, expiry, etc., can be stored in the table. In case one wants to reduce the load on the DB and improve the response time, one can use in-memory databases like Redis on the server.
JWT: It is a definitely a clever way to securely get the identity of the client. In simple language, there is a secret Key used to encrypt the JSON formatted Data, which primarily includes the user-id.
Now an encryption of data with the Key generates the token that is sent to the client and is used in every request. Every time the client sends in the request with the token, the server tries to decrypt it with the Key. If it can, it gets the user-id from the JSON Data, which corresponds to the user.
Badly Created JWT GIF
NOTE: The actual working of the JWT is not so straightforward: it actually involves Public/Secret Keys, where the Payload is signed by the secret. For actual details, please Google or Wiki.
Pros
- No Database Table: this implies fewer DB queries, which implies faster response time. In case you are using paid services like DynamoDb that charge per query basis, JWT might reduce the costs marginally.
However, these can be resolved using tools like Redis in case of sessions. - Simpler to use if you're careful : If your architecture doesn’t use client Sessions and your security basics are clear, the development time in case of JWT is faster using the existing libraries.
- Used across services: You can have one authorization server that deals with the Login/Registration and generates the token. None of the subsequent requests will need to go to the authorization server, as only the Auth-server will have have the private key, and rest of the severs will have the public-key to verify the signature.
This is really useful in case of corporate systems, where the authorization server is in a secure environment, e.g., a user needs to be connected to the intranet to login, but once done, the public servers can verify and proceed.
A similar setup can be used for OAuth implementation.
The best part is that there is no connection between the the auth-server and the rest of the servers other than the pre-defined public key.
Cons
- Compromised Secret Key: The best and the worst things about JWT is that it relies on just one Key. Consider that if the Key is leaked by a careless or a rogue developer/administrator, the whole system is compromised!
The attacker (who has access to the Key) can easily access all user data if he has the user-id, which can be easily acquired.
The only way to recover from this is to generate a new Key (Key-pair) that will be used across systems here on out. This would mean all of the existing client tokens are invalidated and each user would have to login again. Imagine one day 100% of Facebook users will be logged out.
Well, you might wonder, why is the same not possible if the developer/administrator leaks the Session table?
It is possible, but it is related to the practicality of the situation. Remember, most online breaches are done with social engineering rather than complicated technical hacks.
a) Practically, it is really difficult to leak the whole table. In case of a single key, the admin just has to pretend to take a photo of his friend in the office aaaaand the secret is on Reddit. The next morning, you fire him.
b) As well consider the OpenSSL Heartbleed bug. It is really easy to extract the secret key from just a couple of memory dumps with a simple string match script. - Cannot manage client from the server: We had several cases where we wanted the users at HelpTap to logout by cleaning up the cookies, but we cannot ask them to do so every time.
As well consider the case that a user’s mobile is stolen, and he wants to logout of all existing sessions (e.g., Gmail’s logout other sessions feature). Well, it's not possible in case of JWT.
In our case, it used to be rogue users. We needed to log them out. Well, in case of of HelpTap, it was quite easy, as we just had to delete the session tokens. There was no way to do the same in case of Bottr, because we used JWT in that case.
You might argue, why not just delete the existing user-id from the table… but doing so means creating multiple dangling pointers... and no one likes dangling pointers in a No-SQL database. - Cannot push Messages to clients: (identifying clients from server) As we have no record about the logged-in clients on the DB end, we cannot push messages to all clients.
In HelpTap, we implemented a chatting platform wherein the client polls the server for new messages. Each client has an AWS SQS queue to itself where we push any new messages. In case of JWT, this would not have been possible as identifying each client per user is not possible.
One can use the device ID but not all clients have a device ID — that would mean creating another table that is parallel to the Session table.
This point overlaps point two. - Crypto-algo can be deprecated: JWT relies completely on the Signing algorithm. Now, though it is not frequent, in the past, many Encryption/Signing algorithms have been deprecated.
This article shows how you can crack the Wifi password of a WEP Encrypted Wifi, which was the most common type of encryption not more than a year ago. The hack was based on the weakness of the crypto algorithm. So, in case of JWT, if such a thing happens, yet again, every user on the platform will have to login again.
Yet again one will have to wait till all of the JWT libraries update with the latest crypto-algo. - Data Overhead : The size of the JWT token will be more than that of a normal Session token. The more data you add in the JWT token, the longer it gets linearly. Remember, each request needs the token in it for request verification. So say, a 1 KB JWT token implies each request will have 1KB over-head upload which is really bad in cases of low speed net connectivity.
In case of bad developers, someone might put more data in the JSON and that would increase the length. The length of the sessions tokens can be as small it can be and still be secure, e.g., the possible combinations for just a 5 letter alphanumeric session string is almost 1 billion combinations (62⁵) - Complicated to understand: JWT uses cryptographic Signature algorithms to verify the data and get the user-id from the token. Understanding the Signing Algo in itself requires basics of cryptography. So, in case if the developer is not completely educated s/he might introduce security loopholes in the system. My co-worker was surprised when I decoded the JWT token without using the secret key. He expected that the whole token was an encrypted one.
I came across a website that stored the whole user object in the JWT token. This included the user’s password hash.
Sessions tokens are pretty straightforward to understand and such issues can be easily avoided.
As JWT is a fairly new concept, one might not find the libraries in all of the languages out there. Adding to it, neither JWT nor Sessions solve the CSRF or XSS issues, as it completely depends on how you send the data.
TL;DR: JWT is fast(development) though less customizable, risky, and slightly complicated to understand.
I don’t think it’s right to say that the JSON is encrypted. The secret is used to encode the data. Anyone can read the payload data. That’s part of why other services can read the JSON data without communicating with the auth service.
Never said that - JSON is encoded.
Sorry for the late reply :-P
After reading this: https://www.owasp.org/index.php/JSON_Web_Token_(JWT)_Cheat_Sheet_for_Java also I’m figuring out that JWT appears simple at first but can becomes very complicated if you want a realy full security proof system… Thanks for sharing :-)