0% found this document useful (0 votes)
379 views34 pages

Jwts Not Safe e Book

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
379 views34 pages

Jwts Not Safe e Book

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

E-Book

JSON Web Tokens


(JWTs) Are Not Safe
An in-depth guide to why security
experts believe JWTs aren’t safe for user
sessions—and a battle-tested alternative

© 2021 Redis
2

Table of Chapter 1:
HTTP Sessions, Authentication, and Authorization. . . . . . 3 Other considerations and issues . . . . . . . . . . . . . . . . . . . . . . . . 14
Contents The use case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 › Length of tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1. Where to store the session data (client vs. database). . . 4 › The state needs to be maintained anyway
2. How to send session data to the client. . . . . . . . . . . . . . . . . . . 5 (for rate-limiting, IP-whitelisting, etc.). . . . . . . . . . . . . . . . 14
3. How the client can send session tokens to the So why is JWT dangerous for user authentication?. . . . 15
server for future requests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Still trying to make JWT work? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4. How the server can handle authentication Bottom line. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
and authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 When can I use JWT?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
5. When will the session expire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 If I can’t use JWT, what else can I do?. . . . . . . . . . . . . . . . . . . . 17
Section summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Chapter 4:
Chapter 2: Storing Sessions in Redis. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Storing Sessions in a Traditional Database. . . . . . . . . . . . . . . . . 7 An example code snippet (Node.js). . . . . . . . . . . . . . . . . . . . . 19
The main problem with this approach:. . . . . . . . . . . . . . . . . . . . . . 8
There are two ways to solve this problem:. . . . . . . . . . . . . . 8 Chapter 5:
› Option 1: Eliminate database lookup (step four): . . . 8 Sessions When Redis Is Your Primary Database. . . . . . . . . 20
› Option 2: Make the database lookup so Is anyone using this architecture?. . . . . . . . . . . . . . . . . . . . . . . . 21
fast that the additional call won’t matter. . . . . . . . . . . . . 9
Chapter 6:
Chapter 3: Using Both Redis and JWT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Storing Sessions in JWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 [1] References:. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Token expiration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
JWT is too liberal for a security spec and About Redis. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
so is vulnerable. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
› The “none” algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
› The algorithms are passed in an array . . . . . . . . . . . . . . . 13
› Claims are optional. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
3

Introduction JSON Web Tokens are popularly used for


managing user sessions. However, there
are many in-depth articles and videos from
subject matter experts (SMEs) of security
companies like Okta talking about the
potential dangers and inefficiencies of
using JWT tokens. Yet, these warnings are
1

overshadowed by marketers, YouTubers,


bloggers, course creators, and others who
knowingly or unknowingly continue to
promote them.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
4

Introduction Below are some examples of SMEs talking about the security problems of JWT:

“To be clear: This article does not argue that


“JSON Web Tokens can be used to validate you should never use JWT—just that it isn’t
user locally without the need for a suitable as a session mechanism, and that it is
database but then you put yourself at risk dangerous to use it like that. Valid usecases do
for massive security issues.” exist for them, in other areas.”

Source: “Why JWTs Are Bad for Authentication”— Source: “Stop using JWT for sessions”
Randall Degges, Head of Developer Advocacy, Okta, (see reference below for links).
a leading enterprise identity provider.

“Adopting them comes


“I don’t care if you want to use stateless client tokens. They’re fine. You with drawbacks. You either
should understand the operational limitations (they may keep you up forgo revocation, or you
late on a Friday scrambling to deploy a token blacklist), but, we’re all need to have infrastructure
adults here, and you can make your own decisions about that. in place that is way more
complex than simply
The issue with JWT in particular is that it doesn’t bring anything to adopting a session store
the table, but comes with a whole lot of terrifying complexity. Worse, and opaque tokens.”
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.”
Source: “JWT should not
be default for your sessions”
(see reference below for links).

Source: Thomas H. Ptacek, a well-known security researcher


on Hacker News (see references below for links).

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
5

Introduction One of the main reasons for JWTs usage is the need for
speed. The other reason is that it’s simple to use. The last
reason is it’s a buzzworthy and friendly name that’s excellent
for marketing. The name combines “JSON” (which is
generally well liked), “Web” (for web), and “Token” (which
implies stateless), and all of this may make people think it’s
perfect for their web authentication. In reality, it’s not.

So this is a case in which the marketers have beaten out the


engineers and security experts.

But it’s not all bad, because there are regular long and
passionate debates about JWT on Hacker News (see here,
here and here), so there is hope. This amount of debate
should give you pause because security should ideally be a
black-and-white issue: either something is secure or it’s not.

By the end of this book, you’ll know the benefits and the
dangers of JWTs, and also the battle-tested solution that
thousands of companies use to overcome this.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
6

Chapter 1
HTTP Sessions, Authentication,
and Authorization
Before we get into JWTs, The use case
Imagine that you are using Twitter. You log in to the
let’s take a look at a use platform, you “like” someone’s tweet, and then you write
case to better understand a new tweet of your own. So you perform two additional
actions after you log in. You need to be authenticated and
sessions, authentication, authorized before you can perform each of the three spe-
and authorization. cific actions. This is because HTTP is a stateless protocol,
which means that the HTTP request doesn’t store who you
are from one request to the next.

Figure 1: In the example at right,


you are making three differ-
ent requests and the server is LOGIN IS LOGIN ALLOWED?
verifying if your request is valid
three different times.
IS LIKING A TWEET
LIKE A TWEET
ALLOWED?

POST A NEW TWEET IS POSTING ALLOWED?

BROWSER SERVER DATABASE

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
7

Chapter 1 After you log in, the servers typically create a session. The session is a container that houses data about the
user’s interaction with the website or service, and, as its name implies, its lifetime is typically bound by the user’s
log in and log out actions. A session typically will have the following information:

• User’s profile information, such as name, date of birth, email address, etc.
• User’s permissions, such as “user,” “admin,” “supervisor,” “super-admin,” etc.
• Other app-related data, such as shopping cart details if it’s a retail app, etc.
• Session expiration, such as one hour from now, one week from now, etc.

Managing sessions presents five major challenges:

1. Session data needs to be stored somewhere.


2. Since HTTP is stateless, session data must be sent back to the client so that the client can keep adding this
information to future requests.
3. The client then needs to send the session data back to the server for future requests.
4. The server needs to verify if the client’s information is valid; that is, “authentication” and “authorization.” For
example, whether or not the user who is liking a tweet is a “user” or “admin,” if the session expired or not, etc.
5. Session expiration. At some point, the session needs to expire to force people to log in again for security reasons.

Let’s look at each of these five points and get a general idea of how they work in most applications.

1. Where to store the session data (client vs. database)


If you send the session data back to the client (say browser or mobile app), then you risk security issues. Someone
could access or intercept the session data, change that data, and access the server. In addition, there could be
a huge amount of data that’s going back and forth between the client and the server. So it needs to be stored in
the backend—typically in a database.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
8

Chapter 1 2. How to send session data to the client


If you create a session in the server (upon login) and then keep that data in the database, how can the client
know about it? In order to solve this problem, servers generate a session token that looks like a random string that
points to the actual session data in the database and sends it back to the client. The server either sends the ses-
sion token in the form of a cookie or an HTTP response.

The session token is an opaque random string that looks something like this:
fsaf12312dfsdf364351312srw12312312dasd1et3423r

In the database, that string points to the entire session data. It will look something like this:

Figure 2: Example of how a User’s session table


session token maps to a session
inside a database.
SESSION TOKEN SESSION

fsaf12312dfsdf364351312srw12312312dasd1et3423r {user_name: raja, email: [email protected],


isAdmin: true, shoppingCart:3, session_
expiration:Aug-25th}

sadfsdfsd24323456456dfdfasda454 {user_name: Mike, email: [email protected],


isAdmin: false, shoppingCart:1, session_
expiration:Aug-22th}

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
9

Chapter 1 3. How the client can send session tokens


to the server for future requests
Once the client receives the session token in the form of a cookie or as a token, it keeps
this information and adds this session token information to every future request.

Figure 3: Example of how


sessions and cookies are BROWSER SERVER
created and stored.
1. LOGIN 2. CREATE SESSION
TOKEN AND COOKIE

4. SEND COOKIE

CookieName: myAppCookie

id: fsaf12312dfsdf364351312srw12312312dasd1et3423r 3. STORE SESSION


httpOnly: true
MaxAge: 24 hours
Path:/

Here is how it works:


1. User logs in.
2. The server creates a session, session token, and cookie.
3. The server then stores the session and the session
token into a database.
4. The server then sends the cookie that internally
contains the session token back to the browser.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
10

Chapter 1 4. How the server can 5. When will the session expire
handle authentication Each session also has an expiration time, which can be
and authorization set by the backend developer as anything from 5 min-
utes to 30 days. After that set time, the session data will
be deleted. And if the user makes a call to perform some
Upon every future request, the server queries the data-
action, typically the user will be denied permission, and
base with the session token to get the actual session back,
most client applications will redirect the user to the login
and then the server checks for two things:
page, forcing them to log in again. And when they log in, a
new session is created with a new expiration time and the
1. You are authenticated: Your login data is still valid
cycle starts over.
(verifies it is not tampered with, not expired, not
logged out, etc.)
Note: If you authenticate using OAuth, you get multiple
2. You are authorized: You can log in but do you have
tokens such as “access token,” “refresh token,” and so on.
permission to do that specific action? (i.e., check if
These are all there to provide finer control of when the
you are an admin, data owner, user, employee, super
session should expire. For example, the client can use the
admin, etc.)
refresh token to extend the session for additional time
instead of logging people out.

Section summary
• HTTP is stateless, so to keep track of a user upon login, a “session” is created.
• A session is data about a user and their activity. It contains who they are, what they are authenticated and
authorized to do, and also to keep track of any specific product-related data.
• Session data is typically stored in a database.
• A “session token” that points to the session is created and sent to the client for future references.
• The client sends this “session token” for every future request (via request header or through a cookie) to
identify the user and other details that are stored in the session.
• The server retrieves the session from the session token by making an additional database call, checks if a valid
session exists, and if the session token and the session itself are valid, it lets the user take future actions, such
as liking a tweet, creating a tweet, etc.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
11

Chapter 2
Storing Sessions in
a Traditional Database
You just learned how sessions work. Now, let’s continue with the Twitter example and see how the entire
process works when you log in to Twitter and submit a tweet.

1. You log in with your username and password:


a. The server first authenticates the user.
b. The server then creates a session token and then stores that token along with the user’s info in some
database.

Note: A session token is a long unidentifiable string—aka opaque string—that looks like this:
fsaf12312dfsdf364351312srw12312312dasd1et3423r

2. The server then sends you a session token to the frontend mobile or web application.
a. This token is then stored in the cookie or in the local storage of the app.
3. Next, say you write and submit a tweet. Along with your tweet, the app will then also send the session
token (through a cookie or a header) so that the server can identify who you are. (But remember that the
token is just a random string, so how can the server know who you are just from the session token?)
4. When the server receives the session token, it won’t know who the user is, so it sends that to the data-
base to retrieve the actual user’s info (such as the userID) from that token.
5. If the user exists and is allowed to complete that action (i.e., send a tweet), the server allows them to do
the action.
6. Finally, it tells the frontend that the tweet was sent.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
12

Chapter 2

Figure 4: Illustrating the end- Login Scenario


to-end flow of using a regular
database as a session store.

1. USERNAME + PASSWORD 1.A. AUTHENTICATE USER

2. SEND SESSION 1.B. STORE SESSION AND


TOKEN TO THE APP USER INFO IN THE DB
BROWSER
OR MOBILE SERVER DATABASE
APP

Send a Tweet

3. SESSION TOKEN +
4. SEND SESSION TOKEN
TWEET TEXT

6. TWEET SUCCESSFULLY
SAVED 4.A. SEND USER INFO
BROWSER SERVER TO SERVER
OR MOBILE DATABASE
APP
5. SAVE TWEET TO DB

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
13

Chapter 2 The main problem with Option 1: Eliminate database lookup (step four)

this approach There are three different ways of achieving option 1:

The main problem with this approach is that step four is 1. Store the state in the server’s memory. However, this
slow and needs to be repeated for every single action can cause issues when you scale since this state is only
the user does. So every API call leads to at least two slow available on a specific server.
DB calls, which can slow down the overall response time. 2. Use “sticky sessions.” This is when you instruct the
load balancer to always direct the traffic to a specific
There are two ways to solve this problem: server even after you scale up. Again, this can cause
1. Somehow eliminate database lookup for users different scaling issues and if the server goes down
completely (i.e., eliminate step four). (scale down), you’ll lose all the sessions.
2. Make the extra database lookup much faster so that 3. Use JSON Web Tokens. We’ll investigate how to do this
the additional hop won’t matter. in the following chapter.

Option 2: Make the database lookup so fast


that the additional call won’t matter

Simply use Redis. Tens of thousands of companies use


Redis for session storage. With sub-milliseconds latency,
it’s as if you are storing this data in the server itself. We’ll
look into this more later.

In the next chapter we’ll learn about how JWT works,


including its perceived benefits as well as potential risks.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
14

Chapter 3
Storing Sessions in JWT

JWT, especially when used as a session, attempts the client and the server can see the user info part of
to solve the problem of time-consuming repeated the token, the second part, the signed part, can only be
database calls by completely eliminating the database verified by the server. In the example below, the pink
lookup altogether. section of the token contains the payload (user’s info) and
can be seen by both the client and the server.
The main idea is to store the user’s info in the session
token itself. This means, instead of some long, random But the blue part is signed using a secret string, the
string, the actual user info is passed in the session token header, and the payload itself. And so if the client tampers
itself. And to secure it, part of the token is signed using with the payload (say impersonates a different user), the
a secret that’s only known to the server. So even though signature will be different and won’t be authenticated.

Figure 5: Example of the


different sections of the JWT
token.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
15

Chapter 3 The previous image on page 14 shows a JWT token. It includes <header>.<payload>.<signature>. The header
(highlighted in red) and the payload (highlighted in purple) are often not encrypted (and just base64 encoded),
but the signature (highlighted in blue) is signed.

Here is how our use case would look with JWT:

1. You log in with your username and password:


a. The server authenticates the user by querying the database.
b. The server then creates a JWT session token using the user’s info and the secret (no DB is involved).
2. The server then sends you a JWT token to the frontend application. For future activities, the user can just send
the JWT token to identify the user instead of logging in every time.
3. Next, say you again write and submit a tweet. When you send it, along with your tweet’s text, your app will also
send the JWT token (through a cookie or a header) so that the server can identify who you are. But how can
the server know who you are just from the JWT token? Well, part of the token already has the user information.
4. So when the server receives the JWT token, it uses the secret string to validate the signed section and gets
the user info from the payload section, thus eliminating the DB call.
5. If the signature is verified, it allows them to do the action.
6. Finally sends the frontend that the tweet was saved (i.e., the result of the action the user was originally
intended to take)

Going forward for every user action, the server simply verifies the signed section, gets the user info, and lets the
user complete that action, effectively skipping the DB call completely.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
16

Chapter 3

Figure 6: Example of how JWT Login Scenario (JWT)


helps eliminate DB lookup for
session store.

1. USERNAME + PASSWORD 1.A. AUTHENTICATE USER

2. SERVER CREATES A JWT


BROWSER TOKEN AND SENDS IT BACK
OR MOBILE (no DB is involved) SERVER DATABASE
APP

Send a Tweet (JWT)

3. JWT TOKEN +
TWEET TEXT
4. VERIFY IF THE JWT
TOKEN IS VALID, IF SO,
GET THE USER INFO
6. TWEET SUCCESSFULLY DIRECTLY FROM JWT
SAVED
BROWSER
OR MOBILE
APP SERVER 5. SAVE TWEET TO DB DATABASE

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
17

Chapter 3 Token expiration


But there is one additional and important thing to know The JWT spec is similarly written. Instead of being very
about the JWT tokens—it uses an expiration time to strict in enforcing security rules and having built-in best
expire itself, which is typically set from 5 to 30 minutes. practices, it provides a lot of workarounds to allow for
And because it’s self-contained, you can’t easily revoke/ edge cases and a variety of use cases. These workarounds
invalidate/update this expiration time. This is really where in turn can lead to security breaches.
the crux of the problem lies, but let’s look at some other
specification flaws. And just like with HTML, it burdens the backend engineers
and library creators, who must know all the best practices

JWT is too “liberal” for a to avoid these loopholes. However, unlike with HTML, if
people don’t follow those best practices, it could cause a
security spec and therefore lot more damage than a bad rendering, such as allowing
weak authentication.
is vulnerable
The other problem is because the spec itself is so liberal,
The JWT specification is written more like the HTML JWT library creators don’t have a choice but to comply. For
specification. In HTML, if you don’t close an HTML tag (say that reason, backend engineers need to be very careful
a </div>), it’s still valid and the browsers continue to display when using JWT because what might be technically valid
it. The goal is to try to make the “best effort” to render according to the spec might not be secure.
something in the browser instead of throwing an error,
so it’s very “liberal” in that sense. But this causes a lot of On the next page are some examples
problems for browser developers and frontend engineers, of these potential security issues:
although thankfully the worst that can happen is just a bad
webpage rendering.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
18

Chapter 3 1. The “none” algorithm


JWT allows various algorithms to sign the payload. One of them is the “none” algorithm. At a high level, if someone
specifies algorithm “none,” it means that the JWT libraries should ignore validating the signature completely. So all the
attacker needs to do is simply change the algorithm type to “none” and send whatever they want to the server. The
libraries will think that there is no need to validate the signature and will give access.

For example, say the attacker passes “alg” = none in the header. And say you are reading the alg from the request header
shown below (req.header.alg)—which is valid—you could then hit this vulnerability.

Client:

Server:

The solution to this problem is that the backend engineers need to ensure they ignore the “none” algorithm. Even Auth0,
which promotes JWT, got hit with a big security issue (read more about this here: Critical vulnerabilities in JSON Web
Token libraries [Auth0.com]).

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
19

Chapter 3 2. The algorithms are passed in an array


JWT allows specifying algorithms in an array during verification. This opens up another type of attack. It’s complicated
to explain, but the gist is that when you pass algorithms in an array, the library starts to check if one of these algorithms
works for the payload. Apparently, you can exploit it because you can use the RS256 key as HS256 secret. So if you have
the following code, an attacker could use the RS256 token as an HS256 secret and bypass the JWT security test. You can
learn more about this here (also listed in references #9).

The solution is to use just one algorithm, or use two different methods with just one algorithm each, and call two
methods independently.

3. Claims are optional


JWT provides a nice way to organize and ensure different claims
that could help improve security, but they are all optional. For
example, in the sample code to the right, sub, iss, aud, and so on
are all optional. This puts the burden on implementers to follow
best practices. If the spec had made some of them mandatory,
it would have solved a lot of security headaches.

For example, if the “aud” was mandatory, it would force


engineers to think about it and ensure that the JWT for one
service (e.g., “CartService”) doesn’t work for another service
(e.g., “BackOfficeService”). Because these are optional they are
often not required or configured correctly. To fix this, claims
must be set and checked against what is expected.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
20

Chapter 3 Other considerations and issues


1. Length of tokens. In many complex real-world apps, you may need to store a great deal of information, and storing
it in the JWT tokens could exceed the allowed URL length or cookie lengths, leading to problems. Also, you are now
potentially sending a large volume of data on every request.

2. The state needs to be maintained anyway (for rate-limiting, IP-whitelisting, etc.). In many real-world apps, servers
have to maintain the user’s IP and track APIs for rate-limiting and IP-whitelisting. So you’ll need to use a blazing-fast
database anyway. To think your app somehow becomes stateless with JWT is just not realistic.

So why is JWT dangerous for user authentication?


In addition to all the aforementioned issues, the biggest problem with JWT is the token revocation problem. Since it
continues to work until it expires, the server has no easy way to revoke it.

Following are some use cases that could make this dangerous:

1. Logout doesn’t really log you out. Imagine you logged out from Twitter after sending your tweet. You’d think that you
are logged out of the server, but that’s not the case because JWT is self-contained and will continue to work until it
expires. This could be 5 minutes or 30 minutes or whatever the duration that’s set as part of the token. So if someone
gets access to that token during that time, they can continue to use it to authenticate until it expires.
2. Blocking users doesn’t immediately block them. Imagine you are a moderator of Twitter or some online real-time
game where real users are using the system. And as a moderator, you want to quickly block someone from abusing
the system. You can’t, again for the same reason. Even after you block them, the user will continue to have access to
the server until the token expires.
3. JWTs could contain stale data. Imagine the user is an admin and got demoted to a regular user with fewer permis-
sions. Again, this won’t take effect immediately and the user will continue to be an admin until the token expires.
4. JWT’s are often not encrypted. Because of this, anyone able to perform a man-in-the-middle attack and sniff the JWT
now has your authentication credentials. This is made easier because the MITM attack only needs to be completed on
the connection between the server and the client.

There are ways to encrypt JWT tokens called JWE, but when you use this method, the clients (especially browsers and
mobile devices) won’t have a way to decrypt them to see the actual payload. At this point, you are essentially using the
JWT as a regular encrypted session token—at least from the perspective of the web apps and mobile apps.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
21

Chapter 3 Still trying to make JWT work?


Assuming you got past all the spec’s issues and just want The diagram below does a good job of articulating
to solve the expiration issue. One popular solution is to the challenges of using JWT and the issues with all the
store a list of “revoked tokens” in a database and check it workarounds. There are five different ways you can try to
for every call. And if the token is part of that revoked list, make JWT better, but in all five scenarios, you’ll hit one
then block the user from taking the next action. But now bottleneck or another. You should ask yourself, why do
you are making that extra call to the DB to check if the you need to use a type of technology that needs so much
token is revoked, and so this negates the entire purpose of workaround? And by the time you implement all of the
using JWT altogether. workarounds to your satisfaction, you’d lose the benefits
of it to begin with.

A handy dandy (and slightly


…changing the signing …keeping a list of revocations, …just storing an identifier in … storing it in Local Storage …making them expire very
sarcastic) flow chart about why key when a user needs to accessible to my servers, so I the token, and storing the instead of a cookie, so that I quickly, so that a compromised
“your solution” doesn’t work. invalidate their sessions. can validate tokens. data server-side. have far more space. token is not a very big deal.

I think I can make JWT work for


Your blacklisting/
sessions by… authentication server
goes down. What now?
Assume that any Assume that any
unknown token is valid. unknown token is invalid.

Figure 7. Source: Stop using SECURITY PROBLEM POINTLESS SECURITY PROBLEM USABILITY PROBLEM
JWT for sessions, part 2: Why
Once the attacker takes out Congratulations! You’ve Unlike cookies, which are If your user goes offline for just
your solution doesn’t work the server, he has free roam, reinvented sessions, with all protected from this, any a few minutes, they will have to
and there’s nothing you can do their problems (notably, their JavaScript on the page can login again when they return.
to stop him. need for centralized state), steal it. Including CDN scripts!
and gained nothing in the
process. But…

“But I can just change the signing key.” “I’ll just use refresh tokens.”

USABILITY PROBLEM SECURITY PROBLEM SECURITY PROBLEM


“So then I’ll just have
Sure, except now EVERY a unique signing The implementation you are You can’t revoke the long-term
key for every user,
SINGLE USER has been logged using is less battle-tested, tokens, which means you’re
and base it on
out. For every time a user gets their password, and you run a higher risk of back to square one.
compromised. username or hash!” vulnerabilities.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
22

Chapter 3 Bottom line


Although JWT does eliminate the database lookup, it introduces security issues and
other complexities while doing so, therefore making it risky to use for user sessions.

When can I use JWT?


There are scenarios when it might make sense to use JWT, such as when you are doing
server-to-server (or microservice-to-microservice) communication in the backend and
one service could generate a JWT token to send it to a different service for authorization
purposes. Or other specific scenarios, such as a reset password, for which you can send
a JWT token as a one-time, short-lived token to verify the user’s email.

If I can’t use JWT, what else can I do?


The solution is to not use JWT at all for session purposes. But instead, use the traditional
but battle-tested way to more efficiently make the database lookup so blazing fast (sub-
millisecond) that the additional call won’t matter.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
23

Chapter 4
Storing Sessions in Redis

If the answer to the problem we’ve outlined so far is to use What you need is a database that can serve millions of
the tried-and-true method (i.e., store the sessions in a data- requests in sub-milliseconds. Thousands of companies,
base), but to make that database lookup so fast that the ad- serving billions of users, use Redis for this exact purpose.
ditional call won’t matter, how exactly can this be achieved? With Redis, the additional database call is so fast that it no
longer presents a problem.

Redis as a Session store Login Scenario


(plus rate-limiter, etc.)
BROWSER SERVER DATABASE
Figure 8: Example of the OR MOBILE
APP
complete step-by-step flow of 1. Username + password 1.a Authenticate user
using Redis as a session store.
2. Send session token to the app 1.b Store session and
Note that the lightning icon user info in the DB
indicates a blazing-fast speed,
and the snail icon indicates
slow speed.
Send a Tweet

BROWSER SERVER DATABASE


OR MOBILE 4. Send session token
APP
3. Session token + tweet text
4.a Send user info to server

6. Tweet successfully saved

5. Save tweet to DB

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
24

Chapter 4 Here is how storing a session in Redis works

1. You log in with your username and password:


The server first authenticates the user.
› The server then creates a session token and stores that token along with the user’s info in Redis. It’ll look something
like this:
i. SET sess:12345 “{user:raja, shopping:3, DOB: 1/1/21}”
ii. Where
• 12345 is the session token ID.
• “session:12345” is the Redis key.
• “{user: raja, shopping:3, DOB: 1/1/21}” is the value.
2. The server then sends you a session token to the frontend mobile or web application.
› This token is then stored in the cookie or in the local storage of the app.
3. Next, say you write and submit a tweet as in our previous example. Along with your tweet, your app will also send the
session token (through a cookie or a header) so that the server can identify who you are. But, as before, the token is
just a random string, so how can the server use it to identify you?
4. When the server receives the session token, it won’t know who the user is, so it sends that to Redis to retrieve the actual
user’s info (like userID) from that token.
› GET session:12345
› “{user:raja, shopping:3, DOB: 1/1/21}” //Response from Redis
5. If the user exists and is allowed to complete the action (i.e., send a tweet), the server allows them to do the action.
6. And finally, it tells the frontend that the tweet was sent (with the original response to the original request).

And because Redis is so fast, you don’t need to send large user data back and forth between the client and server—just a
session token is enough. You can get the actual payload from Redis in micro-seconds or sub-milliseconds. Since you are
not sending the data to the client, it’s harder for people to steal. And since the actual data is inside Redis, you don’t have
to depend on session expiration time, you can just verify it against the Redis database itself. And finally, you can delete
the user data from Redis when they log out, so you can always be sure of authentication and authorization.

As you can see, it’s an age-old approach of storing the data in a database, but by making it blazing fast, you effectively
eliminate the speed issue. And it has no security vulnerabilities like JWT.

Since people have been using Redis for session storage for ages, there are plenty of examples of how to implement this in
virtually all languages and frameworks. But here is a simple overview of how to store data in sessions in NodeJS. It works the
same way in every language.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
25

Chapter 4 An example code snippet (Node.js)


1. Import Redis module, create a redisClient, and then create a session.

Source: https://github.com/tj/connect-redis

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
26

Chapter 4 2. Store whatever user information you want into the session and it will be stored in
Redis. The example below shows page view count (req.session.views++) being stored
as part of the session data. So every time this page is visited, the count will increase.

Similarly, you can add req.session.userName, req.session.shoppingCartCount, and set


additional properties and associated value to each property and store them all within
the session. For example, you may add req.session.productName = “JSBook”, req.sesion.
quantity = “3”, rea.session.totalPrice= “$30”, etc.

Source: https://github.com/expressjs/session#reqsession

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
27

Chapter 5
Sessions When Redis Is
Your Primary Database
Redis has been the leading database for caching and session storage for more than a decade now. But over the last
few years, Redis has evolved into a primary multi-model database that offers seven officially supported modules. For
example, you can use RedisJSON (10X faster vs. the market leader) and essentially have a real-time MongoDB-like
database, or use the RediSearch module (4X to 100X faster) and implement real-time full-text search like Algolia.

With Redis as your primary database, everything becomes blazing fast—not just your session storage. In this architecture, all
the application’s primary data and the sessions data—as well as everything else—lives side-by-side in the same database.

Redis as a Primary DB Login Scenario

Figure 9: How using Redis as a BROWSER SERVER REDIS


primary database simplifies the OR MOBILE
APP
overall architecture. 1. Username + password 1.a Authenticate user

1.b Store session and


2. Send session token user info in the DB
to the app

Send a Tweet

BROWSER SERVER REDIS


OR MOBILE 4. Send session token
APP
3. Session token + tweet text
4.a Send user info to server
6. Tweet successfully saved
5. Save tweet to DB

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
28

Chapter 5 1. You log in with your username and password:


› The server first authenticates the user by getting the user information from Redis (instead of a slow database).
i. HGET user:01
ii. > username: raja password wer8wrw9werw8wrw //Response
• Imagine the username and (encrypted) password are stored in “user:01” key as a Hashmap.
› The server then creates a session token and stores that token along with the user’s info into Redis. It will look
something like this:
i. SET sess:12345 “{user:raja, shopping:3, DOB: 1/1/21}”
ii. Where
• 12345 is the session token ID.
• “session:12345” is the Redis Key.
• “{user: raja, shopping: 3, DOB: 1/1/21}” is the value.
2. The server then sends you a session token to the frontend mobile or web application.
› This token is then stored in the cookie or in the local storage of the app.
3. Next, say you wrote and submitted a tweet. Then along with your tweet, your app will also send the session token
(through a cookie or a header) so that the server can identify who you are. But the token is just a random string, so
how can the server know who you are just from the session token?
4. When the server receives the session token, it won’t know who the user is, so it sends that to Redis to retrieve (4a) the
actual user’s info (like userID) from that token.
› GET session:12345
› > “{user:raja, shopping:3, DOB: 1/1/21}” //Response from Redis
5. If the user exists and is allowed to do that action (i.e., send a tweet), the server allows them to complete the action.
6. And finally, it tells the frontend that the tweet was sent.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
29

Chapter 5 Is anyone using this architecture?


Redis works with thousands of customers on a daily basis, and although Redis is still primarily used as a secondary
database, we have started to see this new DBless architecture emerge over the last couple of years. It started to get
more momentum as Redis itself became more feature-rich, powerful, and as more people found success. Companies
like Request Metrics have built their entire startup on this architecture and find it incredibly successful. Watch this video
in which Eric Brandes from Request Metrics explains how his company did it.

Learn more about how you can use Redis as a primary database by watching these videos:
• Redis in 100 seconds [2021, 200,000+ views]
• Redis as a Primary DB (Ofer Bengal, CEO, Redis)
• Redis as a Primary DB(Yiftach Shoolman, CTO, Redis)
• Goodbye cache, Redis as a primary DB
• What is DBLess architecture? [2021]
• Can Redis be used as a Primary DB? [2021]

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
30

Chapter 6
Using Both Redis and JWT

In this final chapter we will review another widely used One last thing to note here is that, as mentioned above,
option that provides some of the benefits of JWT but this setup will still make the app vulnerable to potential
removes most of the security issues previously discussed man-in-the-middle attacks between the clients and server
(with the exception of man-in-the-middle attacks). It is because the tokens are not encrypted.
possible to use JWT as a preliminary check while using
Redis as the secondary check. In such a scenario, if the As mentioned earlier, there is a way to encrypt JWT tokens
JWT verification succeeds, the server will still go to Redis called JWE, but when you use this method, the clients
and double-check the information there. However, if the (especially browsers and mobile devices) won’t have a way
JWT verification itself fails, there’s no need to worry about to decrypt them to see the actual payload. At this point,
checking the Redis database. you are essentially using the JWT as a regular encrypted
session token, at least from the perspective of the web
Another benefit of this approach is that you get to use apps and mobile apps.
existing JWT libraries on both the frontend and backend
without having to develop your own custom way of stor- If you are using it for machine-to-machine communica-
ing the data in Redis (although it’s not a big deal). tion, such as with microservices when you want to share
login info between two different services, you can then
share public keys to decrypt and see the JWT data—but
that’s a different use case.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
31

Chapter 6 The best approach is to simply use encrypted sessions


and store them in Redis. If you want to go this route, there
are plenty of libraries that support this.

Figure 10: Example of JWT


+ Redis nodejs libraries from
npmjs.com.

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
32

Chapter 6 In the following example, we will use Redis as the primary DB,
but the process is the same even if you have an additional DB.

JWT + Redis Login Scenario

BROWSER 1.B. REDIS


OR MOBILE SERVER
APP 1. Username + password CREATES A 1.a Authenticate user
JWT TOKEN
AND SENDS IT
TO REDIS FOR 1.c Store JWT into Redis
2. Send session token to the app
STORAGE

Send a Tweet

BROWSER 4. 5. Ask Redis if the REDIS


OR MOBILE SERVER JWT key exists
APP 3. JWT token + tweet text FIRST
VALIDATES
6. Redis tells if the
JWT TOKEN
key exists or not
8. Tweet successfully saved
7. Save tweet to DB only
if the key exists in Redis

User Logs Out

BROWSER 10. REDIS


OR MOBILE SERVER
APP 9. JWT token + user logs out DELETES 10.a Delete JWT key
THE JWT KEY
IN REDIS
IMMEDIATELY
11. Send successful logout

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
33

Chapter 6 There are slightly different implementations of this


depending on the library, but in general this is how the
Tip:
In order to store the JWT token in Redis and also expire it
process works: automatically, use the following format.

1. User logs in using username and password.


SET <key> <value> EX <expiration time in seconds>
a. The server checks if they are valid.
b. The server creates a JWT token (instead of just
regular session tokens). In the example below, we are storing the entire JWT token
c. The server sends the JWT to Redis for storage. as the key (you can also store just parts of it) and storing
2. The server sends the JWT token back to the client. its value as “1” to have some value (this could be anything),
and setting the expiration to one week.
The user sends a tweet:
3. The user sends a tweet (along with the JWT token).
SET sess:<entire JWT key> 1 EX 604,800
4. The server first validates the JWT token.
5. If the JWT token is valid, it then asks if the JWT token
exists in Redis. You can learn more SET options here:
6. Redis tells the server if the token still exists (we don’t https://redis.io/commands/set
need to do any more validations; just checking if the key
exists is sufficient because JWT already does the job).
7. If the key exists, the server saves the tweet to the DB.
8. The server sends a response back to the client saying [1] References:
the tweet was saved.
1. Stop using JWT for sessions
2. JWT should not be your default for sessions
The user logs out: 3. Why JWTs Are Bad for Authentication - Randall Degges (Head of Dev
9. The user then logs out. Relations, Okta)
10. The server immediately deletes the token in Redis. So 4. Stop using JWT for sessions, part 2: Why your solution doesn’t work
5. Thomas H. Ptacek on Hacker News
going forward, step 7 fails.
6. My experience with JSON Web Token
11. The server sends a successful logout response to the 7. Authentication on the Web (Sessions, Cookies, JWT, localStorage, and more)
client. 8. Thomas H. Ptacek’s blog
9. What makes JSON Web Tokens (JWT) secure?
10. Critical vulnerabilities in JSON Web Token libraries [Auth0.com]

Redis E-Book / JSON Web Tokens (JWTs) Are Not Safe © 2021 Redis
About Redis

Data is the lifeline of every business, and Redis helps


organizations reimagine how fast they can process,
analyze, make predictions, and take action on the data
they generate. Redis provides a competitive edge to
any business by delivering open source and enterprise-
grade data platforms to power applications that drive
real-time experiences at any scale. Developers rely on
Redis to build performance, scalability, reliability, and
security into their applications.

Born in the cloud-native era, Redis uniquely enables


users to unify data across multi-cloud, hybrid and global
applications to maximize business potential. Learn more
about Redis at redis.com and sign up for your free trial.

You might also like