SlideShare a Scribd company logo
Cracking JWT tokensCracking JWT tokens
a tale ofa tale of magicmagic,, Node.jsNode.js andand parallel computingparallel computing
London - 11 JUL 2018
Luciano Mammino (Luciano Mammino ( ))@loige@loige
loige.link/jwt-crack-london 1
loige.link/jwt-crack-london
@loige
2
Luciano... who?Luciano... who?
Visit my castles:
-  (@loige)
-  (lmammino)
-
-  (loige.co)
Twitter
GitHub
Linkedin
Blog
Solution Architect at
with @mariocasciaro
with @andreaman87
with @ Podgeypoos79 3
Based on prior workBased on prior work
Chapters 10 & 11 in (book)
2-parts article on RisingStack:
   " "
Node.js design patterns
ZeroMQ & Node.js Tutorial - Cracking JWT Tokens
github.com/lmammino/jwt-cracker
github.com/lmammino/distributed-jwt-cracker
@loige
4
AgendaAgenda
What's JWTWhat's JWT
How it worksHow it works
Testing JWT tokensTesting JWT tokens
Brute-forcing a token!Brute-forcing a token!
@loige
5
  — RFC 7519— RFC 7519
 
is a compact, URL-safe means of representing claims to be
transferred between two parties. The claims in a JWT are
encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON
Web Encryption (JWE) structure, enabling the claims to be
digitally signed or integrity protected with a Message
Authentication Code (MAC) and/or encrypted.
JSON Web Token (JWT)JSON Web Token (JWT)
@loige
6
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZX
NzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDCNzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDC
Hkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8AHkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8A
@loige
7
OKOK
Let's try to make itLet's try to make it
simpler...simpler...
@loige
8
JWT is...
An URL safe, stateless protocol
for transferring claims
@loige
9
@loige
10
URL safe?
@loige
10
URL safe?
stateless?
@loige
10
URL safe?
stateless?
claims?
@loige
10
URL Safe...URL Safe...
It's a string that can be safely used as part of a URLIt's a string that can be safely used as part of a URL
(it doesn't contain URL separators like "(it doesn't contain URL separators like "==", "", "//", "", "##" or "" or "??")")
unicorntube.pl/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
@loige
11
Stateless?Stateless?
Token validity can be verified without having to interrogate aToken validity can be verified without having to interrogate a
third-party servicethird-party service
(Sometimes also defined as "self-contained")
@loige
12
What is a claim?What is a claim?
@loige
13
some information to transfersome information to transfer
identityidentity (login session)(login session)
authorisation to perform actionsauthorisation to perform actions (api key)(api key)
ownershipownership (a ticket belongs to somebody)(a ticket belongs to somebody)
@loige
14
also...also...
validity constraintsvalidity constraints
token time constraintstoken time constraints (dont' use before/after)(dont' use before/after)
audienceaudience (a ticket only for a specific concert)(a ticket only for a specific concert)
issuer identityissuer identity (a ticket issued by a specific reseller)(a ticket issued by a specific reseller)
@loige
15
also...also...
protocol informationprotocol information
Type of tokenType of token
AlgorithmAlgorithm
@loige
16
In generalIn general
All the bits of information transferred with the tokenAll the bits of information transferred with the token
@loige
17
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZX
NzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDCNzYWdlIjoiaGVsbG8gcGVvcGxlIn0.II7XQbjvDC
Hkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8AHkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8A
@loige
18
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..eyJtZXeyJtZX
NzYWdlIjoiaGVsbG8gcGVvcGxlIn0NzYWdlIjoiaGVsbG8gcGVvcGxlIn0..II7XQbjvDCII7XQbjvDC
Hkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8AHkt3UOh6weHY6tRcemT0gxRVmA6W6uZ8A
3 parts3 parts
separated by "."separated by "."
@loige
19
@loige
20
HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpeyJhbGciOiJIUzI1NiIsInR5cCI6Ikp
XVCJ9XVCJ9
@loige
20
HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpeyJhbGciOiJIUzI1NiIsInR5cCI6Ikp
XVCJ9XVCJ9
PAYLOADPAYLOAD::
eyJtZXNzYWdlIjoiaGVsbG8gcGVvceyJtZXNzYWdlIjoiaGVsbG8gcGVvc
GxlIn0GxlIn0
@loige
20
HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpeyJhbGciOiJIUzI1NiIsInR5cCI6Ikp
XVCJ9XVCJ9
PAYLOADPAYLOAD::
eyJtZXNzYWdlIjoiaGVsbG8gcGVvceyJtZXNzYWdlIjoiaGVsbG8gcGVvc
GxlIn0GxlIn0
SIGNATURESIGNATURE::
II7XQbjvDCHkt3UOh6weHY6tRcemII7XQbjvDCHkt3UOh6weHY6tRcem
T0gxRVmA6W6uZ8AT0gxRVmA6W6uZ8A
@loige
20
HeaderHeader andand PayloadPayload areare
encodedencoded
let's decode them!let's decode them!
Base64UrlBase64Url
@loige
21
@loige
22
HEADERHEADER::
@loige
22
HEADERHEADER::
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
@loige
22
HEADERHEADER::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
@loige
22
HEADERHEADER::
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
@loige
22
HEADERHEADER::
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
eyJtZXNzYWdlIjoiaGVsbG8gcGVvceyJtZXNzYWdlIjoiaGVsbG8gcGVvc
GxlIn0GxlIn0
@loige
22
HEADERHEADER::
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
{"message":"hello people"}{"message":"hello people"}
@loige
22
HEADERHEADER::
The decoded info is JSON!The decoded info is JSON!
PAYLOADPAYLOAD::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
{"message":"hello people"}{"message":"hello people"}
@loige
22
HEADERHEADER::
{"alg":"HS256","typ":"JWT"}{"alg":"HS256","typ":"JWT"}
alg:alg: the kind of algorithm usedthe kind of algorithm used
"HS256""HS256" HMACSHA256 SignatureHMACSHA256 Signature (secret based hashing)(secret based hashing)
""RS256RS256" RSASHA256 Signature" RSASHA256 Signature (public/private key hashing)(public/private key hashing)
""nonenone" NO SIGNATURE!" NO SIGNATURE! (This is " (This is " ")")infamousinfamous
@loige
23
PAYLOADPAYLOAD::
{"message":"hello people"}{"message":"hello people"}
  
Payload can be anything thatPayload can be anything that
you can express in JSONyou can express in JSON
@loige
24
PAYLOADPAYLOAD::
"registered" (or standard) claims:"registered" (or standard) claims:
iss: issuer ID ("auth0")
sub: subject ID ("johndoe@gmail.com")
aud: audience ID ("https://someapp.com")
exp: expiration time ("1510047437793")
nbf: not before ("1510046471284")
iat: issue time ("1510045471284")
@loige
25
PAYLOADPAYLOAD::
"registered" (or standard) claims:"registered" (or standard) claims:
{ 
  "iss": "auth0", 
  "sub": "johndoe@gmail.com", 
  "aud": "https://someapp.com", 
  "exp": "1510047437793", 
  "nbf": "1510046471284", 
  "iat": "1510045471284" 
}
@loige
26
So far it's just metadata...So far it's just metadata...
What makes it safe?What makes it safe?
@loige
27
SIGNATURESIGNATURE::
II7XQbjvDCHkt3UOh6weHY6II7XQbjvDCHkt3UOh6weHY6
tRcemT0gxRVmA6W6uZ8AtRcemT0gxRVmA6W6uZ8A
  
AA Base64URLBase64URL encodedencoded cryptographiccryptographic
signaturesignature of the header and the payloadof the header and the payload
@loige
28
With HS256With HS256
signature = HMACSHA256( 
  base64UrlEncode(header) + "." + 
    base64UrlEncode(payload), 
  secret 
)
header payload secret SIGNATURE+ + =
@loige
29
If a system knows theIf a system knows the secretsecret
It can verify the authenticityIt can verify the authenticity
of the tokenof the token
With HS256With HS256
@loige
30
Let's create a token from scratchLet's create a token from scratch
runkit.com/lmammino/create-jwt-token
@loige
31
Playground for JWTPlayground for JWT
JWT.ioJWT.io
@loige
32
An exampleAn example
Session token
@loige
33
Classic implementationClassic implementation
cookie/session basedcookie/session based
@loige
34
35
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
user:"luciano" 
pass:"mariobros"
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
5. query
id:"Y4sHySEPWAjc" 
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
5. query
id:"Y4sHySEPWAjc" 
6. record
id:"Y4sHySEPWAjc" 
user:"luciano"
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 
@loige
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
2. generate session
id:"Y4sHySEPWAjc" 
user:"luciano"
user:"luciano" 
pass:"mariobros"
3. session cookie
SID:"Y4sHySEPWAjc" 
4. GET /profile
5. query
id:"Y4sHySEPWAjc" 
6. record
id:"Y4sHySEPWAjc" 
user:"luciano"
7. (page)
<h1>hello luciano</h1>
35
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
 
 
 
 
 
 
Sessions
Database
 
 
 
 
 
 
id:"Y4sHySEPWAjc" 
user:"luciano"SID:"Y4sHySEPWAjc" 
@loige
JWT implementationJWT implementation
@loige
36
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
Create Token for "luciano"
Add signature
2. create
JWT
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Create Token for "luciano"
Add signature
2. create
JWT
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Create Token for "luciano"
Add signature
2. create
JWT
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Token says this is "luciano"
Signature looks OK
5. verify
Create Token for "luciano"
Add signature
2. create
JWT
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
6. (page)
<h1>hello luciano</h1>
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Token says this is "luciano"
Signature looks OK
5. verify
Create Token for "luciano"
Add signature
2. create
JWT
@loige
37
 
 
 
 
 
 
Browser
 
 
 
 
 
 
 
1. POST /login
3. JWT Token
{"sub":"luciano"}
user:"luciano" 
pass:"mariobros"
6. (page)
<h1>hello luciano</h1>
 
 
 
 
 
 
Server
 
 
 
 
 
 
 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
4. GET /profile
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJz
dWIiOiJsdWNpYW5vIn0.V92iQaqMrBUhkgEAyRaCY
7pezgH­Kls85DY8wHnFrk4
Token says this is "luciano"
Signature looks OK
5. verify
Create Token for "luciano"
Add signature
2. create
JWT
Note: Only the server
knows the secret
@loige
37
Cookie/sessionCookie/session
Needs a database to store the
session data
The database is queried for every
request to fetch the session
A session is identified only by a
randomly generated string
(session ID)
No data attached
Sessions can be invalidated at any
moment
JWTJWT
Doesn't need a session database
The session data is embedded in
the token
For every request the token
signature is verified
Attached metadata is readable
Sessions can't be invalidated, but
tokens might have an expiry flag
VSVS
@loige
38
Another great JWT use caseAnother great JWT use case
Creating Secure Password Reset LinksCreating Secure Password Reset Links
loige.link/jwt-pwd-reset
@loige
39
JWT LOOKS GREAT!JWT LOOKS GREAT!
But there are pitfalls...But there are pitfalls...
@loige
40
Data is public!Data is public!
@loige
41
Data is public!Data is public!
If you have a token,If you have a token,
you can easily read the claims!you can easily read the claims!
@loige
41
Data is public!Data is public!
If you have a token,If you have a token,
you can easily read the claims!you can easily read the claims!
You only have to Base64Url-decode the
token header and payload
and you have a readable JSON
@loige
41
There's no token database...There's no token database...
  
...if I can forge a token...if I can forge a token
nobody will know it's notnobody will know it's not
authentic!authentic!
@loige
42
DEMODEMO
JWT based web app
github.com/lmammino/sample-jwt-webapp
BUILT WITH
@loige
43
Given an HS256 signed JWTGiven an HS256 signed JWT
We can try to "We can try to "guessguess" the" the secretsecret!!
@loige
44
How difficult can it be?How difficult can it be?
@loige
45
Let's build a distributedLet's build a distributed
JWT token cracker!JWT token cracker!
 
npm.im/distributed-jwt-crackernpm.im/distributed-jwt-cracker
@loige
46
The idea...The idea...
@loige
47
The idea...The idea...
Take a valid JWT tokenTake a valid JWT token
@loige
47
The idea...The idea...
try to "guess" the secret and validate the token against ittry to "guess" the secret and validate the token against it
Take a valid JWT tokenTake a valid JWT token
@loige
47
The idea...The idea...
if the token is validated, then you found theif the token is validated, then you found the secretsecret!!
try to "guess" the secret and validate the token against ittry to "guess" the secret and validate the token against it
Take a valid JWT tokenTake a valid JWT token
@loige
47
The idea...The idea...
YOU CAN NOWYOU CAN NOW CREATE AND SIGNCREATE AND SIGN
ANY JWT TOKENANY JWT TOKEN FOR THISFOR THIS
APPLICATIONAPPLICATION!!
if the token is validated, then you found theif the token is validated, then you found the secretsecret!!
try to "guess" the secret and validate the token against ittry to "guess" the secret and validate the token against it
Take a valid JWT tokenTake a valid JWT token
@loige
47
Magic weaponsMagic weapons
@loige
48
Magic weaponsMagic weapons
Node.jsNode.js
@loige
48
Magic weaponsMagic weapons
Node.jsNode.js ZeroMQZeroMQ
@loige
48
Magic weaponsMagic weapons
Node.jsNode.js
modulemodule
jsonwebtokenjsonwebtoken
ZeroMQZeroMQ
@loige
48
ZeroMQZeroMQ
an open source embeddablean open source embeddable networkingnetworking
librarylibrary and aand a concurrency frameworkconcurrency framework
@loige
49
The brute force problemThe brute force problem
"virtually infinite" solutions space"virtually infinite" solutions space
all the strings (of any length) that can be generated within a given alphabet
(empty string), a, b, c, 1, aa, ab, ac, a1, ba, bb, bc, b1, ca, cb, cc, c1, 1a, 1b, 1c, 11, aaa,
aab, aac, aa1, aba, ...
@loige
50
bijection (int) ⇒(string)bijection (int) ⇒(string)
if we sort all the possible strings over an alphabet
 
Alphabet = [a,b]
0 ⟶ (empty string) 
1 ⟶ a 
2 ⟶ b 
3 ⟶ aa 
4 ⟶ ab 
5 ⟶ ba 
6 ⟶ bb
7 ⟶ aaa
8 ⟶ aab
9 ⟶ aba
10 ⟶ abb 
11 ⟶ baa 
12 ⟶ bab 
13 ⟶ bba 
14 ⟶ bbb 
15 ⟶ aaaa 
16 ⟶ aaab
17 ⟶ aaba
18 ⟶ aabb
...
@loige
51
ArchitectureArchitecture
ServerServer ClientClient
Initialised with a valid JWT token
and an alphabet
coordinates the brute force
attempts among connected clients
knows how to verify a token against
a given secret
receives ranges of secrets to check
@loige
52
Networking patternsNetworking patterns
Router channels:
dispatch jobs
receive results
 
Pub/Sub channel:
termination
signal
@loige
53
Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size)of fixed length (batch size)
@loige
54
Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size)of fixed length (batch size)
0 3 6 9 ...
@loige
54
Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size)of fixed length (batch size)
0
batch 1
3 6 9 ...
@loige
54
Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size)of fixed length (batch size)
0
batch 1 batch 2
3 6 9 ...
@loige
54
Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size)of fixed length (batch size)
0
batch 1 batch 2 batch 3
3 6 9 ...
@loige
54
Server stateServer state
the solution space can be sliced intothe solution space can be sliced into
chunkschunks of fixed length (batch size)of fixed length (batch size)
0
...batch 1 batch 2 batch 3
3 6 9 ...
@loige
54
Initial server stateInitial server state
{ 
  "cursor": 0, 
  "clients": {} 
}
@loige
55
The first client connectsThe first client connects
{ 
  "cursor": 3, 
  "clients": { 
    "client1": [0,2] 
  } 
}
[0,2]
@loige
56
{ 
  "cursor": 9, 
  "clients": { 
    "client1": [0,2],     
    "client2": [3,5],
    "client3": [6,8] 
  } 
}
Other clients connectOther clients connect
[0,2]
[3,5] [6,8]
@loige
57
Client 2 finishes its jobClient 2 finishes its job
{ 
  "cursor": 12, 
  "clients": { 
    "client1": [0,2],     
    "client2": [9,11],
    "client3": [6,8] 
  } 
}
[0,2]
[9,11] [6,8]
@loige
58
let cursor = 0
const clients = new Map()
const assignNextBatch = client => {
const from = cursor
const to = cursor + batchSize - 1
const batch = [from, to]
cursor = cursor + batchSize
client.currentBatch = batch
client.currentBatchStartedAt = new Date()
return batch
}
const addClient = channel => {
const id = channel.toString('hex')
const client = {id, channel, joinedAt: new Date()}
assignNextBatch(client)
clients.set(id, client)
return client
}
Server
@loige
59
Messages flowMessages flow
@loige
60
Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
@loige
60
Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
@loige
60
Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
@loige
60
Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
3. NEXT
@loige
60
Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
3. NEXT
4. BATCH
{nextBatch}
@loige
60
Messages flowMessages flow
 
 
 
JWT Cracker
Server
 
 
 
 
 
 
 
JWT Cracker
Client
 
 
 
 
1. JOIN
2. START
{token, alphabet, firstBatch}
3. NEXT
4. BATCH
{nextBatch}
5. SUCCESS
{secret}
@loige
60
const router = (channel, rawMessage) => {
const msg = JSON.parse(rawMessage.toString())
switch (msg.type) {
case 'join': {
const client = addClient(channel)
const response = {
type: 'start',
id: client.id,
batch: client.currentBatch,
alphabet,
token
}
batchSocket.send([channel, JSON.stringify(response)])
break
}
case 'next': {
const batch = assignNextBatch(clients.get(channel.toString('hex')))
batchSocket.send([channel, JSON.stringify({type: 'batch', batch})])
break
}
case 'success': {
const secret = msg.secret
// publish exit signal and closes the app
signalSocket.send(['exit', JSON.stringify({secret, client: channel.toString('hex')})], 0, () => {
batchSocket.close()
signalSocket.close()
exit(0)
})
break
}
}
}
Server
@loige
61
let id, variations, token
const dealer = rawMessage => {
const msg = JSON.parse(rawMessage.toString())
const start = msg => {
id = msg.id
variations = generator(msg.alphabet)
token = msg.token
}
const batch = msg => {
processBatch(token, variations, msg.batch, (secret, index) => {
if (typeof secret === 'undefined') {
// request next batch
batchSocket.send(JSON.stringify({type: 'next'}))
} else {
// propagate success
batchSocket.send(JSON.stringify({type: 'success', secret, index}))
exit(0)
}
})
}
switch (msg.type) {
case 'start':
start(msg)
batch(msg)
break
case 'batch':
batch(msg)
break
}
}
Client
@loige
62
How a chunk is processedHow a chunk is processed
Given chunk [3,6] over alphabet "ab"
[3,6] ⇒
3 ⟶ aa 
4 ⟶ ab 
5 ⟶ ba 
6 ⟶ bb
⇠check if one of the
strings is the secret
that validates the
current token
@loige
63
const jwt = require('jsonwebtoken')
const generator = require('indexed-string-variation').generator;
const variations = generator('someAlphabet')
const processChunk = (token, from, to) => {
let secret
for (let i = from; i < to; i++) {
try {
secret = variations(i)
jwt.verify(token, secret, {
ignoreExpiration: true,
ignoreNotBefore: true
})
// finished, password found
return ({found: secret})
} catch (err) {} // password not found, keep looping
}
// finished, password not found
return null
}
Client
@loige
64
DemoDemo
@loige
65
Closing offClosing off
@loige
66
Is JWT safe to use?Is JWT safe to use?
@loige
67
DefinitelyDefinitely
YES!YES!
Heavily used by:
@loige
68
but...but...
@loige
69
Use a strong (≃long)Use a strong (≃long) secretsecret and keep it SAFE! and keep it SAFE!
Or, even better
Use RS256 (RSA public/private key pair) signatureUse RS256 (RSA public/private key pair) signature
Use it wisely!Use it wisely!
@loige
70
But, what if I createBut, what if I create
onlyonly
short lived tokensshort lived tokens......
@loige
71
JWT is STATELESS!JWT is STATELESS!
the expiry time is contained in the token...
if you can edit tokens, you can extend the expiry time as needed!
@loige
72
Should I be worried aboutShould I be worried about
brute forcebrute force??
@loige
73
Some benchmarksSome benchmarks
Secret length Attempts Time*
5 26^5 =  12 mln 1m55.618s
6 26^6 = 310 mln 1h32m48.378s
7 26^7 = 8 Bln 3d18h22m10.231s
8 26^8 = 210 Bln ⏱ still running...
9 26^9 = 5.5 Tln I didn't even dare to try!
* 8 clients on 4 t2.medium AWS machines, [a-z] alphabet ( )loige.link/jwt-bench
@loige
74
@loige
75
If you useIf you use a 64a 64 chars  secretchars  secret......
@loige
75
If you useIf you use a 64a 64 chars  secretchars  secret......
26^64 =
3.616.548.304.479.297.085.365.330.736.464.680.499.909.051.89
5.704.748.593.486.634.912.486.670.341.490.423.472.351.870.976
@loige
75
If you useIf you use a 64a 64 chars  secretchars  secret......
26^64 =
3.616.548.304.479.297.085.365.330.736.464.680.499.909.051.89
5.704.748.593.486.634.912.486.670.341.490.423.472.351.870.976
3.63.6 GAZILLIONGAZILLION attempts needed!attempts needed!
@loige
75
If you useIf you use a 64a 64 chars  secretchars  secret......
26^64 =
3.616.548.304.479.297.085.365.330.736.464.680.499.909.051.89
5.704.748.593.486.634.912.486.670.341.490.423.472.351.870.976
3.63.6 GAZILLIONGAZILLION attempts needed!attempts needed!
@loige
75
TLDR;TLDR;
JWT is aJWT is a cool & stateless™cool & stateless™ way toway to
transfer claims!transfer claims!
 
Choose the right Algorithm
With HS256, choose a good secret and keep it safe
Don't disclose sensitive information in the payload
Don't be too worried about brute force, but understand how it works!
@loige
76
Thanks!
@loige@loige
https://loige.cohttps://loige.co
loige.link/jwt-crack-london
77
an      heartfelt thank you to:
"the amazing" Paul Dolan
@mariocasciaro
@AlleviTommaso
@andreaman87
@cirpo
@katavic_d
@Podgeypoos79
@quasi_modal
CreditsCredits
vector imagesvector images
designed by freepikdesigned by freepik
@loige
78

More Related Content

Similar to Cracking JWT tokens: a tale of magic, Node.js and parallel computing - FullStack London, 11 July 2018 (20)

PDF
Cracking JWT tokens: a tale of magic, Node.js and parallel computing - Code E...
Luciano Mammino
 
PDF
Cracking JWT tokens: a tale of magic, Node.JS and parallel computing - Node.j...
Luciano Mammino
 
PDF
2016 pycontw web api authentication
Micron Technology
 
PDF
Javascript Object Signing & Encryption
Aaron Zauner
 
PPTX
In-Toto OpenChain Presentation 03-18-2019
Shane Coughlan
 
PDF
How to implement golang jwt authentication and authorization
Katy Slemon
 
PDF
支撐英雄聯盟戰績網的那條巨蟒
Toki Kanno
 
PDF
Bot 甘苦談,使用者至上
Maxis Kao
 
PDF
JSON Web Tokens
Ivan Rosolen
 
PPTX
Pentesting jwt
Jaya Kumar Kondapalli
 
PDF
sf bay area dfir meetup (2016-04-30) - OsxCollector
Rishi Bhargava
 
PDF
Rapid Web API development with Kotlin and Ktor
Trayan Iliev
 
KEY
MongoDB In Production At Sailthru
ibwhite
 
PDF
Autenticação com Json Web Token (JWT)
Ivan Rosolen
 
PPTX
xAPI Camp-Four Lines of Code
Anthony Altieri
 
PDF
Luciano Mammino - Cracking JWT tokens: a tale of magic, Node.JS and parallel...
Codemotion
 
PDF
Cracking JWT tokens: a tale of magic, Node.JS and parallel computing
Luciano Mammino
 
PDF
Api
randyhoyt
 
PPTX
“Technical Intro to Blockhain” by Yurijs Pimenovs from Paybis at CryptoCurren...
Dace Barone
 
PDF
stackconf 2021 | Why you should take care of infrastructure drift
NETWAYS
 
Cracking JWT tokens: a tale of magic, Node.js and parallel computing - Code E...
Luciano Mammino
 
Cracking JWT tokens: a tale of magic, Node.JS and parallel computing - Node.j...
Luciano Mammino
 
2016 pycontw web api authentication
Micron Technology
 
Javascript Object Signing & Encryption
Aaron Zauner
 
In-Toto OpenChain Presentation 03-18-2019
Shane Coughlan
 
How to implement golang jwt authentication and authorization
Katy Slemon
 
支撐英雄聯盟戰績網的那條巨蟒
Toki Kanno
 
Bot 甘苦談,使用者至上
Maxis Kao
 
JSON Web Tokens
Ivan Rosolen
 
Pentesting jwt
Jaya Kumar Kondapalli
 
sf bay area dfir meetup (2016-04-30) - OsxCollector
Rishi Bhargava
 
Rapid Web API development with Kotlin and Ktor
Trayan Iliev
 
MongoDB In Production At Sailthru
ibwhite
 
Autenticação com Json Web Token (JWT)
Ivan Rosolen
 
xAPI Camp-Four Lines of Code
Anthony Altieri
 
Luciano Mammino - Cracking JWT tokens: a tale of magic, Node.JS and parallel...
Codemotion
 
Cracking JWT tokens: a tale of magic, Node.JS and parallel computing
Luciano Mammino
 
Api
randyhoyt
 
“Technical Intro to Blockhain” by Yurijs Pimenovs from Paybis at CryptoCurren...
Dace Barone
 
stackconf 2021 | Why you should take care of infrastructure drift
NETWAYS
 

More from Luciano Mammino (20)

PDF
Serverless Rust: Your Low-Risk Entry Point to Rust in Production (and the ben...
Luciano Mammino
 
PDF
Did you know JavaScript has iterators? DublinJS
Luciano Mammino
 
PDF
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
Luciano Mammino
 
PDF
Building an invite-only microsite with Next.js & Airtable - ReactJS Milano
Luciano Mammino
 
PDF
From Node.js to Design Patterns - BuildPiper
Luciano Mammino
 
PDF
Let's build a 0-cost invite-only website with Next.js and Airtable!
Luciano Mammino
 
PDF
Everything I know about S3 pre-signed URLs
Luciano Mammino
 
PDF
Serverless for High Performance Computing
Luciano Mammino
 
PDF
Serverless for High Performance Computing
Luciano Mammino
 
PDF
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
Luciano Mammino
 
PDF
Building an invite-only microsite with Next.js & Airtable
Luciano Mammino
 
PDF
Let's take the monolith to the cloud 🚀
Luciano Mammino
 
PDF
A look inside the European Covid Green Certificate - Rust Dublin
Luciano Mammino
 
PDF
Monoliths to the cloud!
Luciano Mammino
 
PDF
The senior dev
Luciano Mammino
 
PDF
Node.js: scalability tips - Azure Dev Community Vijayawada
Luciano Mammino
 
PDF
A look inside the European Covid Green Certificate (Codemotion 2021)
Luciano Mammino
 
PDF
AWS Observability Made Simple
Luciano Mammino
 
PDF
Semplificare l'observability per progetti Serverless
Luciano Mammino
 
PDF
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
Luciano Mammino
 
Serverless Rust: Your Low-Risk Entry Point to Rust in Production (and the ben...
Luciano Mammino
 
Did you know JavaScript has iterators? DublinJS
Luciano Mammino
 
What I learned by solving 50 Advent of Code challenges in Rust - RustNation U...
Luciano Mammino
 
Building an invite-only microsite with Next.js & Airtable - ReactJS Milano
Luciano Mammino
 
From Node.js to Design Patterns - BuildPiper
Luciano Mammino
 
Let's build a 0-cost invite-only website with Next.js and Airtable!
Luciano Mammino
 
Everything I know about S3 pre-signed URLs
Luciano Mammino
 
Serverless for High Performance Computing
Luciano Mammino
 
Serverless for High Performance Computing
Luciano Mammino
 
JavaScript Iteration Protocols - Workshop NodeConf EU 2022
Luciano Mammino
 
Building an invite-only microsite with Next.js & Airtable
Luciano Mammino
 
Let's take the monolith to the cloud 🚀
Luciano Mammino
 
A look inside the European Covid Green Certificate - Rust Dublin
Luciano Mammino
 
Monoliths to the cloud!
Luciano Mammino
 
The senior dev
Luciano Mammino
 
Node.js: scalability tips - Azure Dev Community Vijayawada
Luciano Mammino
 
A look inside the European Covid Green Certificate (Codemotion 2021)
Luciano Mammino
 
AWS Observability Made Simple
Luciano Mammino
 
Semplificare l'observability per progetti Serverless
Luciano Mammino
 
Finding a lost song with Node.js and async iterators - NodeConf Remote 2021
Luciano Mammino
 
Ad

Recently uploaded (20)

PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PDF
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
PDF
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
PDF
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
July Patch Tuesday
Ivanti
 
PPTX
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PDF
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
July Patch Tuesday
Ivanti
 
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
Ad

Cracking JWT tokens: a tale of magic, Node.js and parallel computing - FullStack London, 11 July 2018