jwt! jwt! let it all out!

Post on 15-Apr-2017

406 Views

Category:

Internet

8 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

Hack Salem | 14 Sep 2016 | @genehack 1

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

Hack Salem | 14 Sep 2016 | @genehack 2

Hi, I'm John

Hack Salem | 14 Sep 2016 | @genehack 3

VP, TechInfinity

Interactive

Hack Salem | 14 Sep 2016 | @genehack 4

So, what's a JWT?

Hack Salem | 14 Sep 2016 | @genehack 5

jwt.io

Hack Salem | 14 Sep 2016 | @genehack 6

WhatDoesThatEvenMean

Hack Salem | 14 Sep 2016 | @genehack 7

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

Made of stuff you already know• JSON Objects

• Cryptographically signed and hashed

• Transmitted during HTTP request

Hack Salem | 14 Sep 2016 | @genehack 9

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

• 3 parts

• header

• payload

• signature

• Example: xxx.yyyyy.zzz

Hack Salem | 14 Sep 2016 | @genehack 10

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

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

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

Putting it all together

Hack Salem | 14 Sep 2016 | @genehack 14

Putting it all together

Hack Salem | 14 Sep 2016 | @genehack 15

More advanced usage• Encrypted payloads (JWE)

• Nested JWT

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

Hack Salem | 14 Sep 2016 | @genehack 16

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

OK,you'vegotmy

attentionHack Salem | 14 Sep 2016 | @genehack 18

HowDoI

UseIt?

Hack Salem | 14 Sep 2016 | @genehack 19

Basic auth/authz usage

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

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

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

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

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

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

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

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

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

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

• New experimental language, Nacre

• Transpiles to Javascript

Hack Salem | 14 Sep 2016 | @genehack 29

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

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

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

BTW,just

kiddingaboutNacre…

Hack Salem | 14 Sep 2016 | @genehack 33

it'sPerl!(of course)

Hack Salem | 14 Sep 2016 | @genehack 34

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

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

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

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

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

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

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

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

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

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

Questions?

Hack Salem | 14 Sep 2016 | @genehack 45

Thanks!

Hack Salem | 14 Sep 2016 | @genehack 46

top related