@adam_englander
Don’t Lose Sleep
Secure Your REST
Adam Englander, iovation
@adam_englander
A Little Background About Me
And APIs
@adam_englander
This is what I looked
like when I started
working on APIs
It was so long ago that SOAP was the
new hotness.
@adam_englander
Over The Years
• 2001 — Global Authentication Service API
• 2008 — Loan Application Ping Tree
• 2010 — Loan Management System API
• 2012 — Advertising Network API
• 2013 — Real Time Loan Risk Assessment API
• 2015 — Decentralized Multi-Factor Authorization API
@adam_englander
Some Were More Secure Than
Others
@adam_englander
Only one would survive today’s
rigorous standards
@adam_englander
Cryptography in APIs
Authentication
Message validation
Data encryption
@adam_englander
Authentication
@adam_englander
Message Based Authentication
• Content specific
methodology
• Not standards based
• No credentials for GET
• Simple user implementation
• Custom backend
implementation
{
"credentials": {
"username": "myuser",
"password": "supersecret"
},
"data": {
"key": "value"
}
}
@adam_englander
HTTP Authentication
• Puts authentication data in the HTTP header
• Basic, Bearer, Digest are popular standards based schemes
• Basic and Digest are susceptible to Man-In-The-Middle attack
• Bearer is becoming more popular as OAuth 2 gains ground
• Custom (non-standard) schemes are possible
@adam_englander
Other Custom Solutions
• Rarely provide more security than HTTP Authentication
• Can’t be readily integrated into frameworks
• Can’t be readily integrated into authentication libraries
@adam_englander
Message Validation
@adam_englander
Most APIs have no message
validation at all
@adam_englander
Homegrown Solution
• Develop your own protocol for providing information necessary to
sign and validate the message
• Usually restricted to a single algorithm
• Algorithm changes tend to be a breaking change
@adam_englander
Message Encryption
@adam_englander
Custom Solution
• Develop your own protocol for providing information necessary to
decrypt the encrypted message
• Usually restricted to a single algorithm
• Algorithm changes tend to be a breaking change
• Requires development team to be highly knowledgeable in
cryptography.
• Often times requires an SDK to make it accessible to implementors
@adam_englander
Stop the Madness
Javascript Object Signing and Encryption (JOSE)
@adam_englander
JOSE provides all the tools
necessary to protect your API
@adam_englander
How?
• HTTP Authentication with JSON Web Token for Authentication
• JSON Web Signature to validate entire request and critical portions
of the response
• JSON Web Encryption to encrypt request and response
• JSON Web Algorithm for future proofing cryptography
• JSON Web Key for credential rotation
@adam_englander
JSON Web Signature (JWS)
JWS is comprised of three segments:
1. Header provides key information, signature algorithm, and
optionally content metadata
2. Payload is the data to be signed
3. Signature of the header and payload
@adam_englander
JSON Web Token (JWT)
• JWT is actually a JSON Web Signature (JWS) package with
standardized payload in the form of Claims.
• Provides for credentials, nonce, timestamp, and duration
• Private claims can be added for extensibility
@adam_englander
JSON Web Encryption (JWE)
JSON Web Encryption contains five segments:
1. Header provides key management mode, key information, key
encryption algorithm, content encryption algorithm, and
optionally content metadata
2. Content Encryption Key (CEK) may contain generated
symmetric keys used for encryption and HMAC that are
encrypted using asymmetric key encryption
@adam_englander
JSON Web Encryption (JWE)
3. Initialization Vector for encrypting the payload
4. Encrypted payload
5. Authentication tag is an HMAC of the header, IV, and encrypted
payload
@adam_englander
JSON Web Algorithm
• Standardized format for expressing encryption and signature
algorithms.
• Used by JWE/JWS with “enc” and “alg” keys in the header.
@adam_englander
JSON Web Key
• Standardized format for expressing keys used for JWE and JWS.
• Provides for key identification.
• Used by JWE/JWS with number of keys in the header which are
determined by the key type.
@adam_englander
Why would I want to do all of
this JOSE nonsense?
@adam_englander
Decoupling
• Authentication, validation, and encryption/decryption are decoupled
from the application logic.
• Decoupled logic can be moved to middleware.
• Controllers only handling business lo only HTTP/JSON which greatly
reduced code complexity
@adam_englander
OSS Libraries
• OSS libraries exist for the heavy lifting
• No writing your own crypto
• Can be a simpler implementation
• Documentation complexity is reduced
@adam_englander
Better Cryptography
• JOSE supports a myriad of symmetric and asymmetric algorithms
• Built to overcome the drawbacks of asymmetric algorithms
• Cryptography done right
• More vetting from security researchers
@adam_englander
Is it all wine and roses?
@adam_englander
No
• Some languages have minimal support for algorithms and strengths
• Some languages have no support for JWE. We had to write our own
minimal Objective-C implementation
• Some good documentation but a good working knowledge requires
reading RFCs
@adam_englander
LaunchKey Case Study
How JOSE Solved All of the Things
@adam_englander
LaunchKey API 1/2
• Built with custom encryption scheme using RSA or AES/CBC
• JWT or Message Based Auth
• Message expiration but no nonce
• Difficult to implement and hard to test
• Partial key rotation that was time based
@adam_englander
LaunchKey API v3
• HTTP Authentication with custom method
• JWT with custom claims for authentication and message validation
• JWT Expiration to reduce nonce memory
• Nonce return in response for replay prevention
• Hierarchical authentication based on JWT issuer/audience
• JWE with RSA/AES encryption
@adam_englander
Request Example Representation
POST /service/v3/auths HTTP/1.1
Content-Type: application/jose
Content-Length: 112
Authorization: IOV-JWT eyJhb.VuYyI6IkEy.OKOaw
eyJhbGciO.Ppd6dIAkG.71lYoW6jA.t-4rRH6GsoXt0.1DGC4k
@adam_englander
JWT Header Example
{

"kid": "09:f7:e0:2f:12:90:be:21:1d:a7:07:a2:66:f1:53:b3",

"alg": "RS256",

"typ": "JWT",

"cty": "JWT"

}
@adam_englander
Key Rotation
• Key ID id provided in request and response
• Current and specific public keys are available via endpoint
• https://api.launchkey.com/public/v3/public-key/09:f7:e0:2f:
12:90:be:21:1d:a7:07:a2:66:f1:53:b3
• https://api.launchkey.com/public/v3/public-key
@adam_englander
Key Rotation
{

"kid": "09:f7:e0:2f:12:90:be:21:1d:a7:07:a2:66:f1:53:b3",

"alg": "RS256",

"typ": "JWT",

"cty": "JWT"

}
/v3/public-key/09:f7:e0:2f:12:90:be:21:1d:a7:07:a2:66:f1:53:b3
@adam_englander
Request Authorization
• Single use JSON Web Token (JWT) in Authorization header as
Authorization scheme IOV-JWT
• RSA key signature
• Hierarchical ACL: Org -> Dir -> Service
• Token ID as nonce
• Private claims: request
@adam_englander
Private Request Claims
• Method
• Path
• Body hash
• Body hash algorithm
• Query parameters
@adam_englander
JWT Request Claims Example
{

"iss": "dir:fd57bffe-7391-47c4-94d0-a0ad4b6bc979",

"sub": "svc:d2083969-b5aa-4753-909d-472ce2517fd1",

"aud": "lka",

"iat": 1234567890,

"nbf": 1234567890,

"exp": 1234567895,

"jti": "bec95e07-cee2-4c77-b080-56a8b24b2e54",

"request": {

"meth": "POST",

"path": "/service/v3/auths",

"func": "S256",

"hash":
"66a045b452102c59d840ec097d59d9467e13a3f34f6494e539ffd32c1bb35f18"

}

}
@adam_englander
Hierarchical Credentials
…

"iss": "dir:fd57bffe-7391-47c4-94d0-a0ad4b6bc979",

"sub": "svc:d2083969-b5aa-4753-909d-472ce2517fd1",

"aud": "lka",
…

@adam_englander
Timestamp and Duration
…

"iat": 1487244120,

"nbf": 1487244120,

"exp": 1487244125,

…
JWT hash stored until expiration to prevent replay attacks.
@adam_englander
Nonce
…
"jti": "bec95e07-cee2-4c77-b080-56a8b24b2e54",

…
@adam_englander
Request Validation
POST /service/v3/auths HTTP/1.1
…
"request": {

"meth": "POST",

"path": "/service/v3/auths",

"func": "S256",

"hash": "66a045b452102c59d840e…"

}

…
@adam_englander
Response Authorization
• Single use JSON Web Token (JWT) in custom header X-IOV-JWT
• RSA key signature
• Hierarchical credentials
• Token ID nonce is echoed
• Private claims: response
@adam_englander
Private Response Claims
• Status Code
• Cache-Control Header
• Location Header
• Body hash
• Body hash algorithm
@adam_englander
Response Example Representation
HTTP/1.1 201 Created
Content-Type: application/jose
Content-Length: 112
Cache-Control: no-cache
Location: /directory/v3/users/518f5d3e-7cdf-4ef1-…
X-IOV-JWT: eyJhb.VuYyI6IkEy.OKOaw
eyJhbGciO.Ppd6dIAkG.71lYoW6jA.t-4rRH6GsoXt0.1DGC4k
@adam_englander
JWT Response Claims Example
{

"iss": "lka",

"sub": "svc:d2083969-b5aa-4753-909d-472ce2517fd1",

"aud": "dir:fd57bffe-7391-47c4-94d0-a0ad4b6bc979",

"iat": 1234567891,

"nbf": 1234567891,

"exp": 1234567896,

"jti": "bec95e07-cee2-4c77-b080-56a8b24b2e54",

"response": {

"status": 201,

"cache": "no-cache",

"location": "/directory/v3/users/518f5d3e-7cdf-4ef1-…",

"func": "S256",

"hash":
"66a045b452102c59d840ec097d59d9467e13a3f34f6494e539ffd32c1bb35f18"

}

}
@adam_englander
Hierarchical Credentials
…

"iss": "lka",

"sub": "svc:d2083969-b5aa-4753-909d-472ce2517fd1",

"aud": "dir:fd57bffe-7391-47c4-94d0-a0ad4b6bc979",
…

@adam_englander
Timestamp and Duration
…

"iat": 1487244121,

"nbf": 1487244121,

"exp": 1487244126,

…
@adam_englander
Nonce
…
"jti": "bec95e07-cee2-4c77-b080-56a8b24b2e54",

…
Nonce is echoed in JTI to allow for detection of Man In The Middle
attacks
@adam_englander
Response Validation
HTTP/1.1 201 Created
Cache-Control: no-cache
Location: /directory/v3/users/518f5d3e-7c…
…
"response": {

"status": 201,

"cache": "no-cache",

"location": "/directory/v3/users/518f5d3e-7c…",

"func": "S256",

"hash": “66a045b452102c59d840ec097d59d9467e13…”

}
…
@adam_englander
JWT Creation Example
$jwt = (new JWTCreator(new Signer(['RS512'])))->sign(

[

'iat' => time(),

'exp' => time() + 5,

'jti' => 'abc123',



],

['alg' => 'RS512'],

JWKFactory::createFromKeyFile(

'./private.key'

)

);
@adam_englander
JWT Validation Example
$checkerManager = new CheckerManager();

$checkerManager->addClaimChecker(new IssuedAtChecker());

$jwtLoader = new JWTLoader(

$checkerManager,

new Verifier(['RS512'])

);

$keySet = new JWKSet();

$keySet->addKey(JWKFactory::createFromKeyFile(

'./public.key'

));

$jws = $jwtLoader->load($jwt, $keySet);

$jwtLoader->verify($jws, $keySet);
@adam_englander
Encrypted Data with JWE
• JWK provides for key rotation
• Combination of RSA and AES encryption is always used
• Algorithms and modes are always the same
• Key size is variable in allowed range
• Response uses same AES key size as request
@adam_englander
JWE Header Example
{

"kid": "09:f7:e0:2f:12:90:be:21:1d:a7:07:a2:66:f1:53:b3",

"alg": “RSA-OAEP-256",

"enc": "A256CBC-HS512",

"cty": “application/json"

}
@adam_englander
JWE Encryption Example
$encrypted = JWEFactory::createJWEToCompactJSON(

"Hello World!",

JWKFactory::createFromKeyFile(

'./public.key'

),

[

'enc' => 'A256CBC-HS512',

'alg' => 'RSA-OAEP-256',

'zip' => 'DEF',

]
);
@adam_englander
JWE Decryption Example
$decrypted = (new Loader)->loadAndDecryptUsingKey(

$encrypted,

JWKFactory::createFromKeyFile(

'./private.key'

),

['RSA-OAEP-256'], // Acceptable algs

['A256CBC-HS512'] // Acceptable encs

);
@adam_englander
Conclusion
• JOSE has made our secure API more secure
• JOSE has made our API easier to use
• JOSE has made our code less complex
• JOSE has homogenized auth and crypto across multiple platforms
regardless of language
@adam_englander
Resources
• https://github.com/Spomky-Labs/jose
• https://pypi.python.org/pypi/pyjwkest
• https://bitbucket.org/b_c/jose4j
• https://tools.ietf.org/wg/jose/
• https://jwt.io/
@adam_englander
If You Want To Follow Up
• @adam_englander
• adam.englander@iovation.com
• https://www.iovation.com/blog/author/aenglander

Con Foo 2017 - Don't Loose Sleep - Secure Your REST