"writing secure apis" armin ronacher, pycon ru 2014

81
Writing Secure APIs Armin Ronacher for PyCon.ru 2014

Upload: it-people

Post on 26-Jan-2015

325 views

Category:

Entertainment & Humor


3 download

DESCRIPTION

 

TRANSCRIPT

Page 1: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Writing SecureAPIs Armin Ronacher

for PyCon.ru 2014

Page 2: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Armin RonacherIndependent Contractor for Splash Damage / Fireteam

Doing Online Infrastructure for Computer Games

lucumr.pocoo.org/talks

Page 3: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

… but does it support SAML?

Page 4: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

≈Why Secure APIs?

Page 5: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Starbucks killed the enencrypted connection

Page 6: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

your enemy surfs on the same Wifi as you

Page 7: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Things to secure:Session CookiesAccess TokensCredit Card Numbers…

Page 8: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

don't be afraid of government,your enemy is sitting on the same Wifi

Page 9: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

?Which type of API?

Page 10: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Web vs Browser Web

Page 11: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

It's all about the CAs

Browsers trust Public CAs

Services should trust Certi!cates

Page 12: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Browser Web

You use HTTPAnd there is a good old browser

Websites, JavaScript APIs, etc.

Page 13: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Web

You use HTTPThere is no browserOr it's a browser under your control

Service to Service communication, Custom APIs, etc.

Page 14: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

If there is no browserI do not need a public CA

Page 15: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

If there is a browser there is not much you can do :'(

Page 16: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

?What does a CA do?

Page 17: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

let's look at something else first

Page 18: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

0Understanding Trust

Page 19: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Authenticity Secrecyvs

Page 20: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Authenticity :the author of the message is the

author the receiver knows and trusts.

Page 21: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Secrecy :nobody besides author and intended

receiver read the message.

Page 22: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Authenticity Secrecy>

Page 23: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

Authenticity:

Eve����������� ������������������  is����������� ������������������  wiretapping

Page 24: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

Secrecy����������� ������������������  without����������� ������������������  Authenticity:

Eve����������� ������������������  is����������� ������������������  wiretapping

but����������� ������������������  she����������� ������������������  can����������� ������������������  also����������� ������������������  change����������� ������������������  messages

Page 25: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

XSignatures

Page 26: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Signatures add:authentication, integrity and non-repudication

Page 27: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

!non-repudication is pointless for APIs

Page 28: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

“Signature without non-repudication’

MAC

Page 29: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Consumer gets shared keySigns request with shared keySends request to serverServer verifies requestServer creates and signs responseClient verifies response

123456

Page 30: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

the key is never on the wire!(Eve is a sad attacker)

Page 31: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

Page 32: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

Eve����������� ������������������  can����������� ������������������  not����������� ������������������  send����������� ������������������  the����������� ������������������  request

Page 33: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

Eve����������� ������������������  can����������� ������������������  send����������� ������������������  the����������� ������������������  request

but����������� ������������������  not����������� ������������������  tell����������� ������������������  Alice

Page 34: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

Eve����������� ������������������  can����������� ������������������  send����������� ������������������  the����������� ������������������  request

multiple����������� ������������������  times

Page 35: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

Eve����������� ������������������  could����������� ������������������  just����������� ������������������  send����������� ������������������  it����������� ������������������  with����������� ������������������  delay

zzz

Page 36: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

Eve����������� ������������������  could����������� ������������������  just����������� ������������������  send����������� ������������������  

it����������� ������������������  with����������� ������������������  delay����������� ������������������  -����������� ������������������  and����������� ������������������  not����������� ������������������  tell����������� ������������������  Alice

zzz

Page 37: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

zzz

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

Eve����������� ������������������  could����������� ������������������  just����������� ������������������  send����������� ������������������  

it����������� ������������������  a����������� ������������������  day����������� ������������������  later����������� ������������������  again

Page 38: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

If����������� ������������������  there����������� ������������������  was����������� ������������������  something����������� ������������������  like����������� ������������������  a����������� ������������������  

different����������� ������������������  version����������� ������������������  of����������� ������������������  Bob,����������� ������������������  Eve����������� ������������������  

could����������� ������������������  send����������� ������������������  it����������� ������������������  there

OB'

Page 39: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Why most of those things don't matter

The core problem is that Eve can wiretap

Even without Eve a client can never know if a message was sent!

Idempotency needs to be implemented anyways

Page 40: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

put the nonce in the cache!

Page 41: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

def handle_request(request):

signature = create_signature(request)

if signature != request.supplied_signature:

abort_with_error()

if not nonce_has_been_used(request.nonce):

perform_modification()

remember_nonce(request.nonce)

result = generate_result()

return generate_response_with_signature(result)

Page 42: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

tSignature Expiration

Page 43: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Make Signatures Expireor you store years and years of nonces

Page 44: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Synchronize your Clocks!

Page 45: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

def verify_message(data):

sig, message = split_signature(data)

reference_sig = calculate_signature(message)

if reference_sig != sig: raise InvalidSignature()

header, payload = split_message(message)

expires_at = get_expiration_time(header)

if expires_at < current_time():

raise SignatureExpired()

return header, payload

Page 46: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Message can only be used onceonly need to remember nonce for signature lifetime

Page 47: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

itsdangerouspypi.python.org/pypi/itsdangerous

Page 48: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

import timefrom itsdangerous import URLSafeSerializer, BadSignature

def get_serializer(): return URLSafeSerializer(secret_key=get_secret_key())

def make_auth_ticket(user_id, expires_in=60): return get_serializer().dumps({ 'user_id': user_id, 'expires_at': time.time() + expires_in, })

def verify_auth_ticket(ticket): data = get_serializer().loads(ticket) if data['expires_at'] < time.time(): raise BadSignature('Ticket expired.') return data['user_id']

Page 49: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

∂Signing killed oAuth 1.0a

Page 50: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

People did not want to sign

Page 51: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

… then only sign on the ServerEnter: Token Based Authentication

Page 52: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Token Based Authentication

requires SSL or another secure transportuses short lived tokens

used for exchanging authentication information

Page 53: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

This is what OAuth 2.0 is

Page 54: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Access Refresh Token&

short����������� ������������������  and����������� ������������������  lives����������� ������������������  for����������� ������������������  one����������� ������������������  day signed,����������� ������������������  complex����������� ������������������  and����������� ������������������  lives����������� ������������������  for����������� ������������������  a����������� ������������������  really����������� ������������������  long����������� ������������������  time����������� ������������������  (eternal)

(also����������� ������������������  called����������� ������������������  bearer����������� ������������������  t

oken)

Page 55: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

OOA OB

E

what's����������� ������������������  the����������� ������������������  worst����������� ������������������  Eve����������� ������������������  can����������� ������������������  do?

pretty����������� ������������������  much����������� ������������������  whatever����������� ������������������  the����������� ������������������  hell����������� ������������������  eve����������� ������������������  wants!

Page 56: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Token Based Authentication is a TradeoffIt ‘limits’ what an attacker can do

Stolen Access Token: ~24 hours of damageRefresh Tokens are only exchanged on Token Refresh

only ever used in combination with SSL!

Page 57: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

import uuidfrom itsdangerous import URLSafeSerializer

def get_serializer(): return URLSafeSerializer(secret_key=get_secret_key())

def make_token(user): token_data = { 'user_id': user.id, 'generation': user.token_generation, } refresh_token = get_serializer().dumps(token_data) access_token = str(uuid.uuid4()) store_token(access_token, token_data) return access_token, refresh_token

Page 58: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

CA/SSL without Public CAs

Page 59: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Certificate Revocations do work!not

Page 60: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Certificate says valid until 2020

Private Key Leaked

Page 61: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Certificate says valid until 2020

Private Key Leaked

Page 62: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Certificate says valid until 2020

Private Key Leaked

Page 63: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

what now?

Page 64: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

treat it like token based authentication

Page 65: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

self signed certificates are good(just not if you deal with normal users)

Page 66: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Become your Own Private CA

Page 67: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

make certificates expireevery 24 hours

Page 68: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

refresh token » root certi!cateaccess token » connection certi!cate

They are not the sameBut you treat them the same

Page 69: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Certi!cate Travels over WirePrivate Key Does Not

Page 70: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

create root certi!catetrust root certi!cate alwayshave a cron job issue certi!cates signed by that root every 12 hoursdistribute them to the web serverscycle certs every 12 hours

how it works:

1

2

3

4

5

6

Page 71: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

you can now looks your private keymaximum damage is ~1 dayyour root's private key is on a box not connected to the internet with all ports closed.

what makes it good:

Page 72: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Survives Heartbleed :-)

Page 73: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

from requests import get

resp = get('https://api.yourserver.com/', verify='your/certificate.bundle')

Apple's crappy OpenSSL always trusts Keychain :-(

Page 74: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

why not with public CAs?

Page 75: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

why trust the whole world?

you need to sign on their shitty web application

on most CAs you pay for each signature

and they are most of the time valid for a year

1234

Page 76: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

#Structure for Security

Page 77: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Request comes inResponse goes out

(you can explain that)

Page 78: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Annotate Views for Security Rules

@requires_role('system_management')def manage_system(request): return Response(...)

Example

Page 79: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Encapsulate Security Systemsclass UpdateUser(IdempotentEndpoint): id = Parameter(UUID) changes = Parameter(dict)

def load_state(self): self.user = fetch_user(self.id)

def update_state(self): self.user.update(self.changes)

def get_response(self, state): return JSONResponse(self.user.to_json())

Example

Page 80: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

Add Security Contextsclass Context(object):

def __init__(self): self.account = None self.role_subset = set()

def load_token(self, token, role_subset): self.account = find_account(token['account_id']) self.role_subset = set(role_subset)

def has_role(self, x): if self.account is None or x not in self.role_subset: return False return x in self.account['roles']

Example

Page 81: "Writing Secure APIs" Armin Ronacher, PyCon Ru 2014

?Feel Free To Ask QuestionsTalk slides will be online on lucumr.pocoo.org/talks

You can find me on Twitter: @mitsuhikoAnd gittip: gittip.com/mitsuhiko

Or hire me: [email protected]