2017 dev nexus_deconstructing_rest_security
Post on 12-Apr-2017
462 Views
Preview:
TRANSCRIPT
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Deconstructing REST SecurityDavid Blevins
Tomitribe
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
“The nice thing about standards is you have so many to choose from.”
- Andrew S. Tanenbaum
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Focus Areas
• Beyond Basic Auth
• Theory of OAuth 2.0
• Introduction of JWT
• Google/Facebook style API security
• Stateless vs Stateful Architecture
• HTTP Signatures
• Amazon EC2 style API security
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Baseline Architecture
1000 users x 3 TPS
4 hops
3000 TPS frontend
12000 TPS backend
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Basic Auth (and its problems)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Basic Auth Message
POST /painter/color/object HTTP/1.1Host: localhost:8443Authorization: Basic c25vb3B5OnBhc3M=User-Agent: curl/7.43.0Accept: */*Content-Type: application/jsonContent-Length: 45
{"color":{"b":255,"g":0,"name":"blue","r":0}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Basic Auth
Password Sent
3000 TPS (HTTP+SSL)
username+password Base64
(no auth)
3000 TPS (LDAP)
12000 TPS (HTTP)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Basic Auth
Password Sent
3000 TPS (HTTP+SSL)
username+password Base64
username+password Base64
15000 TPS (LDAP)
Password Sent
12000 TPS (HTTP)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Basic Auth
Password Sent
3000 TPS (HTTP+SSL)
username+password Base64
IP whitelisting
3000 TPS (LDAP)
12000 TPS (HTTP)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
“Hey, give me all of Joe’s salary information.”
“I don’t know who you are,
… but sure!”
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Latveria Attacks
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Basic Auth - Attacks
Valid Password Sent
3000 TPS (HTTP+SSL) IP
whitelisting
9000 TPS (LDAP)
12000 TPS (HTTP)
Invalid Password Sent
6000 TPS (HTTP+SSL)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 (and its problems)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2 - Password Grant(LDAP)
(Token Store)
POST /oauth2/tokenHost: api.superbiz.ioUser-Agent: curl/7.43.0Accept: */*Content-Type: application/x-www-form-urlencodedContent-Length: 54
grant_type=password&username=snoopy&password=woodstock
HTTP/1.1 200 OKContent-Type: application/json;charset=UTF-8Cache-Control: no-storePragma: no-cache
{"access_token":"2YotnFZFEjr1zCsicMWpAA","expires_in":3600,"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",}
Verify Password
Generate Token
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/object HTTP/1.1Host: api.superbiz.ioAuthoriza>on: Bearer 2YotnFZFEjr1zCsicMWpAAUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 45 {"color":{"b":255,"g":0,"r":0,"name":"blue"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/palette HTTP/1.1Host: api.superbiz.ioAuthoriza>on: Bearer 2YotnFZFEjr1zCsicMWpAAUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 46 {"color":{"b":0,"g":255,"r":0,"name":"green"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/select HTTP/1.1Host: api.superbiz.ioAuthoriza>on: Bearer 2YotnFZFEjr1zCsicMWpAAUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 44 {"color":{"b":255,"g":0,"r":0,"name":"red"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/fill HTTP/1.1 Host: api.superbiz.ioAuthoriza>on: Bearer 2YotnFZFEjr1zCsicMWpAAUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 49 {"color":{"b":255,"g":255,"r":0,"name":"yellow"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/stroke HTTP/1.1Host: api.superbiz.ioAuthoriza>on: Bearer 2YotnFZFEjr1zCsicMWpAAUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 49 {"color":{"b":255,"g":200,"r":0,"name":"orange"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
401
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2 - Refresh Grant(LDAP)
(Token Store)
Verify Password
Generate Token
POST /oauth2/tokenHost: api.superbiz.ioUser-Agent: curl/7.43.0Accept: */*Content-Type: application/x-www-form-urlencodedContent-Length: 54
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
HTTP/1.1 200 OKContent-Type: application/json;charset=UTF-8Cache-Control: no-storePragma: no-cache
{"access_token":"6Fe4jd7TmdE5yW2q0y6W2w","expires_in":3600,"refresh_token":"hyT5rw1QNh5Ttg2hdtR54e",}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Old pair
• Access Token 2YotnFZFEjr1zCsicMWpAA
• Refresh Token tGzv3JOkF0XG5Qx2TlKWIA
New pair
• Access Token 6Fe4jd7TmdE5yW2q0y6W2w
• Refresh Token hyT5rw1QNh5Ttg2hdtR54e
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/palette HTTP/1.1Host: api.superbiz.ioAuthoriza>on: Bearer 6Fe4jd7TmdE5yW2q0y6W2wUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 46 {"color":{"b":0,"g":255,"r":0,"name":"green"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/select HTTP/1.1Host: api.superbiz.ioAuthoriza>on: Bearer 6Fe4jd7TmdE5yW2q0y6W2wUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 44 {"color":{"b":255,"g":0,"r":0,"name":"red"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message
POST /painter/color/fill HTTP/1.1 Host: api.superbiz.ioAuthoriza>on: Bearer 6Fe4jd7TmdE5yW2q0y6W2wUser-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 49 {"color":{"b":255,"g":255,"r":0,"name":"yellow"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
What have we achieved?
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
You have more passwords (at least your devices do)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Term Alert
• Password Grant???
• Logging in
• Token?
• Slightly less crappy password
• Equally crappy HTTP Session ID
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2
Tokens Sent
3000 TPS (HTTP+SSL)
IP whitelisting
3000 TPS (token checks)
Password Sent
1000/daily (HTTP+SSL)
OAuth 2
(LDAP)
4 hops 12000 TPS
backend
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
“Who the heck is
6Fe4jd7TmdE5yW2q0y6W2w
???????”“No idea, dude.Ask the token
server.”
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2
Tokens Sent
3000 TPS (HTTP+SSL)
IP whitelisting
3000 TPS (token checks)
Password Sent
1000/daily (HTTP+SSL)
OAuth 2
(LDAP)
12000 TPS (token checks)
8 hops 24000 TPS
backend
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2
Tokens Sent
3000 TPS (HTTP+SSL)
IP whitelisting
3000 TPS (token checks)
Password Sent
1000/daily (HTTP+SSL)
OAuth 2
(LDAP)
12000 TPS (token checks)
8 hops 24000 TPS
backend
55% of all traffic
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2
Tokens Sent
3000 TPS (HTTP+SSL)
IP whitelisting
0 TPS (token checks)
Password Sent
1000/daily (HTTP+SSL)
OAuth 2
(LDAP)
0 TPS (token checks)
0 hops 0 TPS backend
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2
Pointer Pointer
State
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Access Token Access Pointer?
Access Primary Key?
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 High Frequency Password
Exchange Algorithm?
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Hashing and Signing Symmetric and Asymmetric
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 +
JSon Web Tokens (JWT)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
JSon Web Token
• Pronounced “JOT”
• Fancy JSON map
• Base64 URL Encoded
• Digitally Signed (RSA-SHA256, HMAC-SHA512, etc)
• Built-in expiration
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Access Token Previously
• 6Fe4jd7TmdE5yW2q0y6W2w
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Access Token Now
• eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbi10eXBlIjoiYWNjZXNzLXRva2VuIiwidXNlcm5hbWUiOiJzbm9vcHkiLCJhbmltYWwiOiJiZWFnbGUiLCJpc3MiOiJodHRwczovL2RlbW8uc3VwZXJiaXouY29tL29hdXRoMi90b2tlbiIsInNjb3BlcyI6WyJ0d2l0dGVyIiwibWFucy1iZXN0LWZyaWVuZCJdLCJleHAiOjE0NzQyODA5NjMsImlhdCI6MTQ3NDI3OTE2MywianRpIjoiNjY4ODFiMDY4YjI0OWFkOSJ9.DTfSdMzIIsC0j8z3icRdYO1GaMGl6j1I_2DBjiiHW9vmDz8OAw8Jh8DpO32fv0vICc0hb4F0QCD3KQnv8GVM73kSYaOEUwlW0k1TaElxc43_Ocxm1F5IUNZvzlLJ_ksFXGDL_cuadhVDaiqmhct098ocefuv08TdzRxqYoEqYNo
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Access Token Now
• header (JSON > Base64 URL Encoded) • describes how the token signature can be checked
• payload (JSON > Base64 URL Encoded) • Basically a map of whatever you want to put in it
• Some standard keys such as expiration
• signature (Binary > Base64 URL Encoded • The actual digital signature
• made exclusively by the /oauth2/token endpoint
• If RSA, can be checked by anyone
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
• { "alg": “RS256", "typ": “JWT" } • {
"token-type": "access-token", "username": "snoopy", "animal": "beagle", "iss": "hdps://demo.superbiz.com/oauth2/token", "scopes": [ “twider”, "mans-best-friend" ], "exp": 1474280963, "iat": 1474279163, "j>": "66881b068b249ad9" }
• DTfSdMzIIsC0j8z3icRdYO1GaMGl6j1I_2DBjiiHW9vmDz8OAw8Jh8DpO32fv0vICc0hb4F0QCD3KQnv8GVM73kSYaOEUwlW0k1TaElxc43_Ocxm1F5IUNZvzlLJ_ksFXGDL_cuadhVDaiqmhct098ocefuv08TdzRxqYoEqYNo
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Subtle But High Impact Architectural Change
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
What we had (quick recap)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)Pull User Info
From IDP
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)
Generate an Access Token
(pointer)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)
Insert both into DB
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)
Send Access Token (pointer) to client
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Results
Client Holds Pointer Server Holds State
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
What we can do now (Hello JWT!)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)Pull User Info
From IDP
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)
Format the data as JSON
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)
RSA-SHA 256 sign JSON
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)
Insert only pointer into DB
(for revocation)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
(LDAP)
Send Access Token (state) to client
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Client Holds State Server Holds Pointer
Desired Results
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2 - Password Grant(LDAP)
(Token ID Store)
POST /oauth2/tokenHost: api.superbiz.ioUser-Agent: curl/7.43.0Accept: */*Content-Type: application/x-www-form-urlencodedContent-Length: 54
grant_type=password&username=snoopy&password=woodstock
Verify Password
Generate Signed Token
HTTP/1.1 200 OKContent-Type: application/json;charset=UTF-8Cache-Control: no-storePragma: no-cache
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbi10eXBlIjoiYWNjZXNzLXRva2VuIiwidXNlcm5hbWUiOiJzbm9vcHkiLCJhbmltYWwiOiJiZWFnbGUiLCJpc3MiOiJodHRwczovL2RlbW8uc3VwZXJiaXouY29tL29hdXRoMi90b2tlbiIsInNjb3BlcyI6WyJ0d2l0dGVyIiwibWFucy1iZXN0LWZyaWVuZCJdLCJleHAiOjE0NzQyODA5NjMsImlhdCI6MTQ3NDI3OTE2MywianRpIjoiNjY4ODFiMDY4YjI0OWFkOSJ9.DTfSdMzIIsC0j8z3icRdYO1GaMGl6j1I_2DBjiiHW9vmDz8OAw8Jh8DpO32fv0vICc0hb4F0QCD3KQnv8GVM73kSYaOEUwlW0k1TaElxc43_Ocxm1F5IUNZvzlLJ_ksFXGDL_cuadhVDaiqmhct098ocefuv08TdzRxqYoEqYNo","expires_in":3600,"refresh_token":"eyJhbGctGzv3JOkF0XG5Qx2TlKWIAkF0X.eyJ0b2tlbi10eXBlIjoiYWNjZXNzLXRva2VuIiwidXNlcm5hbWUiOiJzbm9vcHkiLCJhbmltYWwiOiJiZWFnbGUiLCJpc3MiOiJodHRwczovL",}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2.0 Message with JWT
POST /painter/color/palette HTTP/1.1Host: api.superbiz.ioAuthoriza>on: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbi10eXBlIjoiYWNjZXNzLXR va2VuIiwidXNlcm5hbWUiOiJzbm9vcHkiLCJhbmltYWwiOiJiZWFnbGUiLCJpc3MiOiJodHRwczovL2RlbW8uc3VwZXJ iaXouY29tL29hdXRoMi90b2tlbiIsInNjb3BlcyI6WyJ0d2l0dGVyIiwibWFucy1iZXN0LWZyaWVuZCJdLCJleHAiOjE0NzQy ODA5NjMsImlhdCI6MTQ3NDI3OTE2MywianRpIjoiNjY4ODFiMDY4YjI0OWFkOSJ9.DTfSdMzIIsC0j8z3icRdYO1GaMGl 6j1I_2DBjiiHW9vmDz8OAw8Jh8DpO32fv0vICc0hb4F0QCD3KQnv8GVM73kSYaOEUwlW0k1TaElxc43_Ocxm1F5IUNZ vzlLJ_ksFXGDL_cuadhVDaiqmhct098ocefuv08TdzRxqYoEqYNo
User-Agent: curl/7.43.0Accept: */* Content-Type: application/jsonContent-Length: 46 {"color":{"b":0,"g":255,"r":0,"name":"green"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2 + JWT
Tokens Sent
3000 TPS (HTTP+SSL)
IP whitelisting
0.55 TPS (refresh token checks)
Password Sent
1000/daily (HTTP+SSL)
OAuth 2
(LDAP)
4 hops 12000 TPS
backend
3000 TPS (signature verification)
12000 TPS (signature verification)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
“Hey, give me all of Joe’s salary information.”
“Not a chance!”
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
“Hey, give me all of Joe’s salary information.”
“Sure thing!”
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth 2 + JWT
Valid Tokens Sent
3000 TPS (HTTP+SSL)
IP whitelisting
0.55 TPS (refresh token checks)
Password Sent
1000/daily (HTTP+SSL)
(LDAP)
4 hops 12000 TPS
backend
9000 TPS (signature verification)
12000 TPS (signature verification)
Invalid Tokens Sent
6000 TPS (HTTP+SSL)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
http://connect2id.com/products/nimbus-jose-jwt
Great JWT lib
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
HTTP Signatures (Amazon EC2 style API Security)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
HTTP Signatures
• No “secret” ever hits the wire
• Signs the message itself
• Proves identity
• Prevents message tampering
• Symmetric or Asymmetric signatures
• IETF Draft
• https://tools.ietf.org/html/draft-cavage-http-signatures
• Extremely simple • Does NOT eliminate benefits of JWT (they’
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Signature Message
POST /painter/color/palette HTTP/1.1Host: api.superbiz.ioAuthorization: Signature keyId=“my-key-name", algorithm="hmac-sha256", headers="content-length host date (request-target)”, signature="j050ZC4iWDW40nVx2oVwBEymXzwvsgm+hKBkuw04b+w="Date: Mon, 19 Sep 2016 16:51:35 PDT Accept: */* Content-Type: application/jsonContent-Length: 46 {"color":{"b":0,"g":255,"r":0,"name":"green"}}
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Signature closeup
Signature keyId=“my-key-name", algorithm="hmac-sha256", headers="content-length host date (request-target)”, signature="j050ZC4iWDW40nVx2oVwBEymXzwvsgm+hKBkuw04b+w="
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Signature Auth
Password Sent
0 TPS (HTTP)
Signature (no auth)
3000 TPS (LDAP or Keystore)
12000 TPS (HTTP)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Signature Auth
Password Sent
0 TPS (HTTP)
Signature Signature
3000 TPS (LDAP or Keystore)
12000 TPS (HTTP)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
“Hey, give me all of Joe’s salary information.”
“Hey, Larry!
Sure!”
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth and Signatures
Password Sent
3000 TPS (HTTP+SSL)
OAuth 2 Signature
12000 TPS (HTTP)
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
“Hey, give me all of Joe’s salary information.”
“Sure thing, Larry!
Tell Joe I said hi.”
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
OAuth and Signatures
Password Sent
3000 TPS (HTTP+SSL)
OAuth 2 Signature
12000 TPS (HTTP)
Joe
Larry
Stan
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Observations
• HTTP Signatures the only HTTP friendly approach
• Signatures does not solve the “Identity Load” problem
• OAuth 2 with JWT significantly improves IDP load
• Plain OAuth 2
• HTTP Session-like implications
• OAuth 2 with JWT
• Signed cookie
• Signing key to the future
Dev
Nex
us
#RESTSecurity @dblevins @tomitribe
Thank You!
top related