KEMBAR78
Jwt == insecurity? | PDF
JWT == insecurity?
A journey in the insecurity of 

JSON web tokens…
by Louis Nyffenegger
@PentesterLab
louis@pentesterlab.com
Introduction01
Agenda
The JWT format (simplified)02
By Design03
Libraries04
Using Libraries05
Conclusion06
PentesterLab.com / @PentesterLab
About Me
PentesterLab.com / @PentesterLab
Security Engineer:
PentesterLab:
Pentester/Code Reviewer/Security consultant/Security architect
Platform to learn web security/penetration testing
100% Hands-on
Available for individuals (free and PRO) and enterprises
Run a website to help people learn security
JOSE/JWE/JWS/JWT
PentesterLab.com / @PentesterLab
• JOSE:
• Javascript Object Signing and Encryption
• Also the name of the working group
• JWT: JSON Web Token == “jot” Token
• JWE: JSON Web Encryption
• JWS: JSON Web Signature
• JWK: JSON Web Key
• JWA: JSON Web Algorithm
Who uses JWT
PentesterLab.com / @PentesterLab
• A lot of people for OAuth
• A lot of people for sessions
• A lot of people to manage trust
• A lot of people for password reset
• A lot of people who care about being stateless
and multi-datacenter architecture
THE JWT FORMAT
JavaScript Object Notation (JSON)
PentesterLab.com / @PentesterLab
Human readable format to store or transmit objects
The Compact JWS Format
PentesterLab.com / @PentesterLab
Header Payload Signature
3 parts in a JSON Web Token:
The Compact JWS Format
PentesterLab.com / @PentesterLab
Header Payload Signature
Separated by a dot
. .
The Compact JWS Format
PentesterLab.com / @PentesterLab
eyJ0eXAiOiJK
V1QiLCJhbGci
OiJIUzI1NiJ9
eyJsb2dpbi
I6ImFkb
WluIn0
FSfvCBAwypJ4abF6
jFLmR7JgZhkW674
Z8dIdAIRyt1E
Separated by a dot
. .
eyJ = Base64('{"')
The Compact JWS Format
PentesterLab.com / @PentesterLab
Base64({…}) Base64({…}) Base64(…)
Header and Payload are base64* encoded JSON
. .
* urlsafe base64 encoding without padding
The signature is also base64 encoded
The Compact JWS Format: Encoding
PentesterLab.com / @PentesterLab
Urlsafe base64 encoding without padding:
*https://tools.ietf.org/html/rfc7515#appendix-C
The JWT Format: header
PentesterLab.com / @PentesterLab
Base64({"alg": "HS256",
"typ": "JWS"})
The header contains an algorithm “alg” attribute:
In this example HMAC with SHA256 was used
To tell how the token was signed.
…
. . …
The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
A lot of different algorithms are supported*:
None
* https://jwt.io/ covers most
HS256
HS384
HS512
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
Scenario: one client talking to multiple services
The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
HS256
HS384
HS512
HMAC: All services need to know the secret
The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
HS256
HS384
HS512
HMAC: if one service gets compromised
The JWT Format: Algorithms
PentesterLab.com / @PentesterLab
HS256
HS384
HS512
HMAC: the secret is compromised for all services
The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: sharing the key
Private
Public
The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: Only trusted services get the
private key
Private
Public
The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: If one service gets compromised…
Private
Public
The JWT Format: Asymmetric
PentesterLab.com / @PentesterLab
RS256
RS384
RS512
ES256
ES384
ES512
PS256
PS384
PS512
Asymmetric: Even in the browser!
Private
Public
The JWT Format: payload
PentesterLab.com / @PentesterLab
…
The payload may contain literally anything:
Base64({"user":"admin",
"roles": ["adm","users"]}). . …
The JWT Format: payload
PentesterLab.com / @PentesterLab
The payload may contain registered claims:
Base64({"user":"admin",
"exp":12…, "iat":1234.. }). .… …
The JWT Format: payload
PentesterLab.com / @PentesterLab
The payload may contain registered claims:
• “iss”: issuer
• “sub”: subject
• “aud”: audience
• “jti”: claim id
• “exp”: expiration time
• “nbf”: not before
• “iat”: issued at*
* useful for async processing
The JWT Format: creating a token
PentesterLab.com / @PentesterLab
• Create the JSON header and base64 encode it
• Create the JSON payload and base64 encode it
• Concatenate with a dot the (encoded) header
and payload
• Sign the result (header+.+payload)
• Base64 encode the signature
• Append a dot then the signature
The JWT Format: verifying a token
PentesterLab.com / @PentesterLab
• Split the token in three parts based on the dots
• Base64 decode each part
• Parse the JSON for the header and payload
• Retrieve the algorithm from the header
• Verify the signature based on the algorithm
• Verify the claims
Keep in mind
PentesterLab.com / @PentesterLab
• Multiple systems can issue tokens
• A token can be used by multiple systems
• All these systems can use different libraries
By Design
By design: verifying signature
PentesterLab.com / @PentesterLab
Base64({ "alg": "HS256",
"typ": "JWS"})
You need to base64 decode and parse
JSON to verify the signature:
Larger attack surface
JSON.load vs JSON.parse, Base64 decoding
…
. . …
By design: verifying signature
PentesterLab.com / @PentesterLab
The attacker controls the algorithm used:
Downgrade attacks, confusion attack
Base64({ "alg": "HS256",
"typ": "JWS"})
…
. . …
By design: Confusion attack
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token signed with RSA (you only have
access to the public key)
• Decode the header and change the algorithm
from RSA “RS256” to HMAC “HS256”
• Tamper with the payload
• Sign the token with the public RSA key
• Profit
By design: verifying signature
PentesterLab.com / @PentesterLab
…
Claims are optionals and not always supported*:
Always-valid tokens?
Base64({"user":"admin",
"exp":12…, "iat":1234.. }). . …
* Check https://jwt.io/
By design: verifying signature
PentesterLab.com / @PentesterLab
Claims are optionals
and not always
supported*
Always-valid tokens?
* Check https://jwt.io/
By design: verifying signature
PentesterLab.com / @PentesterLab
Signed data: you cannot (easily) manage quick-
revocation*:
The claim “jti” and a cache can be used to limit
the impact of this
No quick-revocation! Replay
* Unless you rotate the key or manage a server-side cache
By design: The None algorithm
PentesterLab.com / @PentesterLab
JWT RFC contains a None algorithm
No integrity!
Basically an unsigned token…
By design: The None algorithm
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token
• Decode the header and change the algorithm to
“None” or “none”
• Decode and tamper with the payload
• Keep or remove the signature
• Profit
Libraries
Libraries: CVE-2018-0114
PentesterLab.com / @PentesterLab
JWS allows you to add a “jwk” attribute (JSON Web
Key) to the header to tell the receiver what key was
used to sign the token:
Libraries: CVE-2018-0114
PentesterLab.com / @PentesterLab
• Vulnerability in Cisco Node Jose
• Node-Jose uses the embedded “jwk” key to check
the signature
Integrity bypass!
Libraries: CVE-2018-0114 - Exploitation
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token
• Decode and tamper with the payload
• Generate a RSA key
• Add “n" & “e” to the header and use
RS256
• Sign the token with your RSA key
Libraries: Go-JOSE version <= 1.0.5
PentesterLab.com / @PentesterLab
Non-compact/full format for JWS:
Libraries: Go-JOSE version <= 1.0.5
PentesterLab.com / @PentesterLab
From: https://rwc.iacr.org/2017/Slides/nguyen.quan.pdf
The issue:
Libraries: Go-JOSE version <= 1.0.5
PentesterLab.com / @PentesterLab
From: https://rwc.iacr.org/2017/Slides/nguyen.quan.pdf
The issue:
Integrity of the protected bypass!
Libraries: Go-JOSE version <= 1.0.5
PentesterLab.com / @PentesterLab
If the application trusts the protected*:
* you cannot change the payload
Libraries: Go-JOSE version <= 1.0.5 - Exploitation
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token (compact or full)
• Modify it to use the full format
• Add your malicious protected
• Profit
Using libraries
Using Libraries: weak secret
PentesterLab.com / @PentesterLab
Some developers use weak secrets.
Reminder: you only need one token to brute force
the secret (completely offline)
Integrity bypass!
Using Libraries: decode vs verify
PentesterLab.com / @PentesterLab
A lot of libraries have two functions/methods:
• decode <- don’t use this one
• verify
Integrity bypass!
Using Libraries: decode vs verify
PentesterLab.com / @PentesterLab
Exploitation:
• Get a token
• Decode and tamper with the header or payload
• Profit
Using Libraries: not using exp or iat
PentesterLab.com / @PentesterLab
In many libraries you need to opt-in to use “exp” or
“iat”
Always-valid tokens?
Conclusion
Recommendations
PentesterLab.com / @PentesterLab
✓ Use strong keys and secrets
✓ Review the libraries you pick (KISS library)
✓ Make sure you check the signature
✓ Make sure your tokens expire
✓ Enforce the algorithm
Conclusion
PentesterLab.com / @PentesterLab
• JWT are complex and kind of insecure by design
• JWT libraries introduce very interesting bugs
• Make sure you test for those if you pentest or do
bug bounties
Any questions?
FOR YOUR TIME
THANKS!
louis@pentesterlab.com / PentesterLab.com / @PentesterLab

Jwt == insecurity?

  • 1.
    JWT == insecurity? Ajourney in the insecurity of JSON web tokens… by Louis Nyffenegger @PentesterLab louis@pentesterlab.com
  • 2.
    Introduction01 Agenda The JWT format(simplified)02 By Design03 Libraries04 Using Libraries05 Conclusion06 PentesterLab.com / @PentesterLab
  • 3.
    About Me PentesterLab.com /@PentesterLab Security Engineer: PentesterLab: Pentester/Code Reviewer/Security consultant/Security architect Platform to learn web security/penetration testing 100% Hands-on Available for individuals (free and PRO) and enterprises Run a website to help people learn security
  • 4.
    JOSE/JWE/JWS/JWT PentesterLab.com / @PentesterLab •JOSE: • Javascript Object Signing and Encryption • Also the name of the working group • JWT: JSON Web Token == “jot” Token • JWE: JSON Web Encryption • JWS: JSON Web Signature • JWK: JSON Web Key • JWA: JSON Web Algorithm
  • 5.
    Who uses JWT PentesterLab.com/ @PentesterLab • A lot of people for OAuth • A lot of people for sessions • A lot of people to manage trust • A lot of people for password reset • A lot of people who care about being stateless and multi-datacenter architecture
  • 6.
  • 7.
    JavaScript Object Notation(JSON) PentesterLab.com / @PentesterLab Human readable format to store or transmit objects
  • 8.
    The Compact JWSFormat PentesterLab.com / @PentesterLab Header Payload Signature 3 parts in a JSON Web Token:
  • 9.
    The Compact JWSFormat PentesterLab.com / @PentesterLab Header Payload Signature Separated by a dot . .
  • 10.
    The Compact JWSFormat PentesterLab.com / @PentesterLab eyJ0eXAiOiJK V1QiLCJhbGci OiJIUzI1NiJ9 eyJsb2dpbi I6ImFkb WluIn0 FSfvCBAwypJ4abF6 jFLmR7JgZhkW674 Z8dIdAIRyt1E Separated by a dot . . eyJ = Base64('{"')
  • 11.
    The Compact JWSFormat PentesterLab.com / @PentesterLab Base64({…}) Base64({…}) Base64(…) Header and Payload are base64* encoded JSON . . * urlsafe base64 encoding without padding The signature is also base64 encoded
  • 12.
    The Compact JWSFormat: Encoding PentesterLab.com / @PentesterLab Urlsafe base64 encoding without padding: *https://tools.ietf.org/html/rfc7515#appendix-C
  • 13.
    The JWT Format:header PentesterLab.com / @PentesterLab Base64({"alg": "HS256", "typ": "JWS"}) The header contains an algorithm “alg” attribute: In this example HMAC with SHA256 was used To tell how the token was signed. … . . …
  • 14.
    The JWT Format:Algorithms PentesterLab.com / @PentesterLab A lot of different algorithms are supported*: None * https://jwt.io/ covers most HS256 HS384 HS512 RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512
  • 15.
    The JWT Format:Algorithms PentesterLab.com / @PentesterLab Scenario: one client talking to multiple services
  • 16.
    The JWT Format:Algorithms PentesterLab.com / @PentesterLab HS256 HS384 HS512 HMAC: All services need to know the secret
  • 17.
    The JWT Format:Algorithms PentesterLab.com / @PentesterLab HS256 HS384 HS512 HMAC: if one service gets compromised
  • 18.
    The JWT Format:Algorithms PentesterLab.com / @PentesterLab HS256 HS384 HS512 HMAC: the secret is compromised for all services
  • 19.
    The JWT Format:Asymmetric PentesterLab.com / @PentesterLab RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512 Asymmetric: sharing the key Private Public
  • 20.
    The JWT Format:Asymmetric PentesterLab.com / @PentesterLab RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512 Asymmetric: Only trusted services get the private key Private Public
  • 21.
    The JWT Format:Asymmetric PentesterLab.com / @PentesterLab RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512 Asymmetric: If one service gets compromised… Private Public
  • 22.
    The JWT Format:Asymmetric PentesterLab.com / @PentesterLab RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512 Asymmetric: Even in the browser! Private Public
  • 23.
    The JWT Format:payload PentesterLab.com / @PentesterLab … The payload may contain literally anything: Base64({"user":"admin", "roles": ["adm","users"]}). . …
  • 24.
    The JWT Format:payload PentesterLab.com / @PentesterLab The payload may contain registered claims: Base64({"user":"admin", "exp":12…, "iat":1234.. }). .… …
  • 25.
    The JWT Format:payload PentesterLab.com / @PentesterLab The payload may contain registered claims: • “iss”: issuer • “sub”: subject • “aud”: audience • “jti”: claim id • “exp”: expiration time • “nbf”: not before • “iat”: issued at* * useful for async processing
  • 26.
    The JWT Format:creating a token PentesterLab.com / @PentesterLab • Create the JSON header and base64 encode it • Create the JSON payload and base64 encode it • Concatenate with a dot the (encoded) header and payload • Sign the result (header+.+payload) • Base64 encode the signature • Append a dot then the signature
  • 27.
    The JWT Format:verifying a token PentesterLab.com / @PentesterLab • Split the token in three parts based on the dots • Base64 decode each part • Parse the JSON for the header and payload • Retrieve the algorithm from the header • Verify the signature based on the algorithm • Verify the claims
  • 28.
    Keep in mind PentesterLab.com/ @PentesterLab • Multiple systems can issue tokens • A token can be used by multiple systems • All these systems can use different libraries
  • 29.
  • 30.
    By design: verifyingsignature PentesterLab.com / @PentesterLab Base64({ "alg": "HS256", "typ": "JWS"}) You need to base64 decode and parse JSON to verify the signature: Larger attack surface JSON.load vs JSON.parse, Base64 decoding … . . …
  • 31.
    By design: verifyingsignature PentesterLab.com / @PentesterLab The attacker controls the algorithm used: Downgrade attacks, confusion attack Base64({ "alg": "HS256", "typ": "JWS"}) … . . …
  • 32.
    By design: Confusionattack PentesterLab.com / @PentesterLab Exploitation: • Get a token signed with RSA (you only have access to the public key) • Decode the header and change the algorithm from RSA “RS256” to HMAC “HS256” • Tamper with the payload • Sign the token with the public RSA key • Profit
  • 33.
    By design: verifyingsignature PentesterLab.com / @PentesterLab … Claims are optionals and not always supported*: Always-valid tokens? Base64({"user":"admin", "exp":12…, "iat":1234.. }). . … * Check https://jwt.io/
  • 34.
    By design: verifyingsignature PentesterLab.com / @PentesterLab Claims are optionals and not always supported* Always-valid tokens? * Check https://jwt.io/
  • 35.
    By design: verifyingsignature PentesterLab.com / @PentesterLab Signed data: you cannot (easily) manage quick- revocation*: The claim “jti” and a cache can be used to limit the impact of this No quick-revocation! Replay * Unless you rotate the key or manage a server-side cache
  • 36.
    By design: TheNone algorithm PentesterLab.com / @PentesterLab JWT RFC contains a None algorithm No integrity! Basically an unsigned token…
  • 37.
    By design: TheNone algorithm PentesterLab.com / @PentesterLab Exploitation: • Get a token • Decode the header and change the algorithm to “None” or “none” • Decode and tamper with the payload • Keep or remove the signature • Profit
  • 38.
  • 39.
    Libraries: CVE-2018-0114 PentesterLab.com /@PentesterLab JWS allows you to add a “jwk” attribute (JSON Web Key) to the header to tell the receiver what key was used to sign the token:
  • 40.
    Libraries: CVE-2018-0114 PentesterLab.com /@PentesterLab • Vulnerability in Cisco Node Jose • Node-Jose uses the embedded “jwk” key to check the signature Integrity bypass!
  • 41.
    Libraries: CVE-2018-0114 -Exploitation PentesterLab.com / @PentesterLab Exploitation: • Get a token • Decode and tamper with the payload • Generate a RSA key • Add “n" & “e” to the header and use RS256 • Sign the token with your RSA key
  • 42.
    Libraries: Go-JOSE version<= 1.0.5 PentesterLab.com / @PentesterLab Non-compact/full format for JWS:
  • 43.
    Libraries: Go-JOSE version<= 1.0.5 PentesterLab.com / @PentesterLab From: https://rwc.iacr.org/2017/Slides/nguyen.quan.pdf The issue:
  • 44.
    Libraries: Go-JOSE version<= 1.0.5 PentesterLab.com / @PentesterLab From: https://rwc.iacr.org/2017/Slides/nguyen.quan.pdf The issue: Integrity of the protected bypass!
  • 45.
    Libraries: Go-JOSE version<= 1.0.5 PentesterLab.com / @PentesterLab If the application trusts the protected*: * you cannot change the payload
  • 46.
    Libraries: Go-JOSE version<= 1.0.5 - Exploitation PentesterLab.com / @PentesterLab Exploitation: • Get a token (compact or full) • Modify it to use the full format • Add your malicious protected • Profit
  • 47.
  • 48.
    Using Libraries: weaksecret PentesterLab.com / @PentesterLab Some developers use weak secrets. Reminder: you only need one token to brute force the secret (completely offline) Integrity bypass!
  • 49.
    Using Libraries: decodevs verify PentesterLab.com / @PentesterLab A lot of libraries have two functions/methods: • decode <- don’t use this one • verify Integrity bypass!
  • 50.
    Using Libraries: decodevs verify PentesterLab.com / @PentesterLab Exploitation: • Get a token • Decode and tamper with the header or payload • Profit
  • 51.
    Using Libraries: notusing exp or iat PentesterLab.com / @PentesterLab In many libraries you need to opt-in to use “exp” or “iat” Always-valid tokens?
  • 52.
  • 53.
    Recommendations PentesterLab.com / @PentesterLab ✓Use strong keys and secrets ✓ Review the libraries you pick (KISS library) ✓ Make sure you check the signature ✓ Make sure your tokens expire ✓ Enforce the algorithm
  • 54.
    Conclusion PentesterLab.com / @PentesterLab •JWT are complex and kind of insecure by design • JWT libraries introduce very interesting bugs • Make sure you test for those if you pentest or do bug bounties
  • 55.
    Any questions? FOR YOURTIME THANKS! louis@pentesterlab.com / PentesterLab.com / @PentesterLab