46
JWT! JWT! Let it all out! John SJ Anderson | @genehack | Hack Salem | 14 Sep 2016 Hack Salem | 14 Sep 2016 | @genehack 1

JWT! JWT! Let it all out!

Embed Size (px)

Citation preview

Page 1: JWT! JWT! Let it all out!

JWT! JWT!Let it all out!John SJ Anderson | @genehack | Hack Salem | 14 Sep 2016

Hack Salem | 14 Sep 2016 | @genehack 1

Page 2: JWT! JWT! Let it all out!

JSON Web Tokenswant to rule your worldJohn SJ Anderson | @genehack | Hack Salem | 14 Sep 2016

Hack Salem | 14 Sep 2016 | @genehack 2

Page 3: JWT! JWT! Let it all out!

Hi, I'm John

Hack Salem | 14 Sep 2016 | @genehack 3

Page 4: JWT! JWT! Let it all out!

VP, TechInfinity

Interactive

Hack Salem | 14 Sep 2016 | @genehack 4

Page 5: JWT! JWT! Let it all out!

So, what's a JWT?

Hack Salem | 14 Sep 2016 | @genehack 5

Page 6: JWT! JWT! Let it all out!

jwt.io

Hack Salem | 14 Sep 2016 | @genehack 6

Page 7: JWT! JWT! Let it all out!

WhatDoesThatEvenMean

Hack Salem | 14 Sep 2016 | @genehack 7

Page 8: JWT! JWT! Let it all out!

Think of it as…• A lightweight alternative to cookies

• A form of access control without authentication

• Cross-site single sign on (SSO) without cross domain pain

Hack Salem | 14 Sep 2016 | @genehack 8

Page 9: JWT! JWT! Let it all out!

Made of stuff you already know• JSON Objects

• Cryptographically signed and hashed

• Transmitted during HTTP request

Hack Salem | 14 Sep 2016 | @genehack 9

Page 10: JWT! JWT! Let it all out!

JWT teardown• dot-delimited string ('.')

• 3 parts

• header

• payload

• signature

• Example: xxx.yyyyy.zzz

Hack Salem | 14 Sep 2016 | @genehack 10

Page 11: JWT! JWT! Let it all out!

JWT teardown: header• Plain ole JSON object

• Base64Url encoded

• Typically indicates token type and hashing algorithm{ "alg": "HS256", "typ": "JWT"}

Hack Salem | 14 Sep 2016 | @genehack 11

Page 12: JWT! JWT! Let it all out!

JWT teardown: payload• Also plain ole JSON object

• Contains "claims" -- really just data

• Reserved, public, private

• Also Base64Url encoded{ "name": "Hack Salem", "admin": false}

Hack Salem | 14 Sep 2016 | @genehack 12

Page 13: JWT! JWT! Let it all out!

JWT teardown: signature• Encoded header, plus

• Encoded payload, plus

• A secret, plus

• Signing algorithm from headerHMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Hack Salem | 14 Sep 2016 | @genehack 13

Page 14: JWT! JWT! Let it all out!

Putting it all together

Hack Salem | 14 Sep 2016 | @genehack 14

Page 15: JWT! JWT! Let it all out!

Putting it all together

Hack Salem | 14 Sep 2016 | @genehack 15

Page 16: JWT! JWT! Let it all out!

More advanced usage• Encrypted payloads (JWE)

• Nested JWT

(Won't get any further into these tonight…)

Hack Salem | 14 Sep 2016 | @genehack 16

Page 17: JWT! JWT! Let it all out!

Libraries for DAYS• .NET, Python, Node, Java, Javascript, Ruby, Perl, Go, PHP

• Haskell, Rust, Lua, Scala, Clojure, ObjectiveC, Swift, Delphi• Support for your favorite language/platform is probably not

an issue

Hack Salem | 14 Sep 2016 | @genehack 17

Page 18: JWT! JWT! Let it all out!

OK,you'vegotmy

attentionHack Salem | 14 Sep 2016 | @genehack 18

Page 19: JWT! JWT! Let it all out!

HowDoI

UseIt?

Hack Salem | 14 Sep 2016 | @genehack 19

Page 20: JWT! JWT! Let it all out!

Basic auth/authz usage

(stolen from jwt.io)Hack Salem | 14 Sep 2016 | @genehack 20

Page 21: JWT! JWT! Let it all out!

Things to be aware of• Payload/header NOT encrypted (in this setup)

• …don't send anything sensitive!

• Need to control expiration, re-issue, etc.

• Some APIs will send a fresh JWT to the client per-request• Sites other than issuing site can receive JWT

• …if they share the secret

Hack Salem | 14 Sep 2016 | @genehack 21

Page 22: JWT! JWT! Let it all out!

How is it actually transmitted?• Up to you! Various methods:

• As part of the URL

• In the POST body

• In the Authorization header using bearer scheme:

Authorization: Bearer <token>

Hack Salem | 14 Sep 2016 | @genehack 22

Page 23: JWT! JWT! Let it all out!

Authorization without authentication

• Scenario:

• You have an API

• You don't want to make anybody authenticate to use it

• You don't want it wide open to the Internet either

• a/k/a authz without authn

Hack Salem | 14 Sep 2016 | @genehack 23

Page 24: JWT! JWT! Let it all out!

Solution: JWT with RSA keys• Alternative to secret in previous scenario: RSA key-pair

• Can include the public key in the JWT header using JWK

• JSON Web Key, natch

• Allows API client to produce claims in a verifiable way

Hack Salem | 14 Sep 2016 | @genehack 24

Page 25: JWT! JWT! Let it all out!

To set it up:• Give authorized user a RSA key-pair

• You can even let them generate it — you just need to:

• Record the fingerprint of the public key (important later!)

Hack Salem | 14 Sep 2016 | @genehack 25

Page 26: JWT! JWT! Let it all out!

On their side:• They make JWT using the private key

• They include the public key in the header

• Include iat (issued-at) and exp (expires) claims

• Send JWT in Authorization header with API request

Hack Salem | 14 Sep 2016 | @genehack 26

Page 27: JWT! JWT! Let it all out!

On our side:• Get the public key out of the JWT header

• Validate the JWT signature using the key

• Validate that public key fingerprint is white-listed

• Signature produced with private key

• Public key is white-listed

• Therefore we know JWT is valid!

Hack Salem | 14 Sep 2016 | @genehack 27

Page 28: JWT! JWT! Let it all out!

Things to be aware of:• You still want to validate iat and exp and any other rules

• Your library should probably do that stuff for you, mostly

• Again, nothing is encrypted, so don't plan on sensitive stuff in the payload or header

Hack Salem | 14 Sep 2016 | @genehack 28

Page 29: JWT! JWT! Let it all out!

Let's see some code!• May look a bit strange

• New experimental language, Nacre

• Transpiles to Javascript

Hack Salem | 14 Sep 2016 | @genehack 29

Page 30: JWT! JWT! Let it all out!

Client side my $pri_key = Crypt::PK::RSA->new('./key.pri'); my $pub_key = Crypt::PK::RSA->new('./key.pub');

my $token = encode_jwt( alg => 'RS512', extra_headers => { jwk => $pub_key->export_key_jwk('public', 1), nonce => undef , }, key => $pri_key , payload => { iat => time() }, relative_exp => 1800, );

HTTP::Request->new( 'POST' => 'https://example.com/endpoint', ['Authorization' => "Bearer $token"], encode_json({ request => 'body' }) );

Hack Salem | 14 Sep 2016 | @genehack 30

Page 31: JWT! JWT! Let it all out!

Client side: making the token my $token = encode_jwt( alg => 'RS512', extra_headers => { jwk => $pub_key->export_key_jwk('public', 1), nonce => undef , }, key => $pri_key , payload => { iat => time() }, relative_exp => 1800, );

Hack Salem | 14 Sep 2016 | @genehack 31

Page 32: JWT! JWT! Let it all out!

Client side: adding the public key extra_headers => { jwk => $pub_key->export_key_jwk('public', 1), },

Key: find an RSA library that supports export to JWK format!

Hack Salem | 14 Sep 2016 | @genehack 32

Page 33: JWT! JWT! Let it all out!

BTW,just

kiddingaboutNacre…

Hack Salem | 14 Sep 2016 | @genehack 33

Page 34: JWT! JWT! Let it all out!

it'sPerl!(of course)

Hack Salem | 14 Sep 2016 | @genehack 34

Page 35: JWT! JWT! Let it all out!

Server side my $auth_header = request_header 'Authorization' ;

status_401 unless ( $token ) = $auth_header =~ /^Bearer (.*)$/;

# try to decode it and confirm valid sig, # and valid iat and exp claims my( $header, $payload ); try { ( $header, $payload ) = decode_jwt( token => $token , decode_header => 1 , accepted_alg => 'RS512' , verify_iat => 1 , verify_exp => 1 ); };

# no catch block, just drop the error, we're out of here in that case status_401 unless $header and $payload;

# check that expiration time is less than one hour status_401 unless $payload->{exp} - $payload->{iat} < 3600;

# check that the included public key is on the whitelist my $pk = Crypt::PK::RSA->new; $pk->import_key($header->{jwk}); my $thumbprint = $pk->export_key_jwk_thumbprint; status_401 unless config->{whitelist}{$thumbprint};

# if we get here, we're all good! ...

Hack Salem | 14 Sep 2016 | @genehack 35

Page 36: JWT! JWT! Let it all out!

Server side: get the token my $auth_header = request_header 'Authorization' ;

status_401 unless ( $token ) = $auth_header =~ /^Bearer (.*)$/;

Hack Salem | 14 Sep 2016 | @genehack 36

Page 37: JWT! JWT! Let it all out!

Server side: decode the token # try to decode it and confirm valid sig, # and valid iat and exp claims my( $header, $payload ); try { ( $header, $payload ) = decode_jwt( token => $token , decode_header => 1 , accepted_alg => 'RS512' , verify_iat => 1 , verify_exp => 1 ); };

# no catch block, just drop the error, we're out of here in that case status_401 unless $header and $payload;

Hack Salem | 14 Sep 2016 | @genehack 37

Page 38: JWT! JWT! Let it all out!

Server side: decode the token• Key in header wrong? FAILS• Not right algorithm? FAILS• Doesn't have iat and exp? FAILSALL that validation is happening inside the library, so I don't have to worry about it.

• Me? WINS

Hack Salem | 14 Sep 2016 | @genehack 38

Page 39: JWT! JWT! Let it all out!

Server side: do more checks # check that expiration time is less than one hour status_401 unless $payload->{exp} - $payload->{iat} < 3600;

# check that the included public key is on the whitelist my $pk = Crypt::PK::RSA->new; $pk->import_key($header->{jwk}); my $thumbprint = $pk->export_key_jwk_thumbprint; status_401 unless config->{whitelist}{$thumbprint};

Hack Salem | 14 Sep 2016 | @genehack 39

Page 40: JWT! JWT! Let it all out!

Server side: more checks• We specify in the API docs that tokens can only be valid for

one hour

• Have to check that ourselves

• Also need to make sure this isn't some random RSA keypair

• Need to make sure we know this public key

Hack Salem | 14 Sep 2016 | @genehack 40

Page 41: JWT! JWT! Let it all out!

Server side: THAT'S ALL FOLKS # if we get here, we're all good!

• If we know the public key in the header,

• then we know the private key was used to sign the JWT

• (or it wouldn't validate)

• and therefore the JWT is from the private key holder

• (who is, by definition, authorized!)

Hack Salem | 14 Sep 2016 | @genehack 41

Page 42: JWT! JWT! Let it all out!

IMPORTANT NOTE!This does, of course, depend on the client keeping the private key actually private…But access revocation is as simple as removing a public keyprint from the whitelist.

Hack Salem | 14 Sep 2016 | @genehack 42

Page 43: JWT! JWT! Let it all out!

Conclusions• JWTs solve some really common problems.

• JWTs solve them in a pretty elegant way.

• This is really pretty damn cool.

Hack Salem | 14 Sep 2016 | @genehack 43

Page 44: JWT! JWT! Let it all out!

Conclusions• JWTs solve some really common problems.

• JWTs solve them in a pretty elegant way.

• This is really pretty damn cool!!!• You should think about using JWTs.

Hack Salem | 14 Sep 2016 | @genehack 44

Page 45: JWT! JWT! Let it all out!

Questions?

Hack Salem | 14 Sep 2016 | @genehack 45

Page 46: JWT! JWT! Let it all out!

Thanks!

Hack Salem | 14 Sep 2016 | @genehack 46