Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Distributed Web Security with Macaroons

Distributed Web Security with Macaroons

This is a presentation given for the KopDar Python Meetup held at IceHouse offices in Jakarta, Indonesia on 21-June-2014. The presentation is intended to provide a brief introduction to macaroons for creating distributed credentials. Complete functionality and documentation offered at the libmacaroons repository. Further details about the concepts behind macaroons are available in the original research paper.

For slides/source/more info, see: https://github.com/shirkey/macaroons-kopdar

shirkey

June 21, 2014
Tweet

More Decks by shirkey

Other Decks in Programming

Transcript

  1. About Purpose - A little about security, authentication and authorization

    - Using macaroons / libmacaroons Me: I'm @shirkeydev ...
  2. Security Aspects Data Confidentiality - access control lists Integrity -

    hashes, checksums Availability - backups, disaster recovery User Authentication - identify users Authorization - credentials, permissions Accounting - audit trail, logging We will be focusing almost exclusively on Authorization in this discussion
  3. Authentication Factors Something you know userid/password PIN number Something you

    have smart card / certificate / bearer tokens handphone via SMS/inbound call Something you are fingerprint , iris scan CAPTCHA Two-factor authentication = any two of these methods used in combination
  4. Successful Authentication => Authorization Credentials After authentication, the user is

    provided credentials for authorization on successive requests Common authorization credential schemes found on the web include: Certificates Cookies Tokens
  5. Credentials: Public-Key Certificates Basically something server administrators look forward to

    administering every year* Pros: agreed upon format established certificate authorities Cons: administration overhead -- installation and portability non-zero cost *certificate revocation every year or earlier (see Heartbleed ) digital-era.net/certificate-revocations-shoot-up-in-wake-of-openssl-heartbleed-bug/ (http://digital-era.net/certificate-revocations-shoot-up-in-wake-of-openssl-heartbleed-bug/)
  6. Credentials: HTTP Cookies Web service creates and provides a unique

    session id as a cookie to the client, session state is maintained on server until token expiration (optional) Pros: simple lightweight Cons: cookies cannot be easily validated between domains
  7. Credentials: Tokens Distributed credentials in the cloud that can be

    shared between users and services Macaroons are token credentials using HMAC signing Pros: - use cookies or other storage mechanism (localStorage/sessionStorage) client-side - can be shared across clients and domains, useful for distributed authorization Cons: - Macaroons are not alone: multiple standards still in draft (JWT, JWS) More Info: tools.ietf.org/html/draft-ietf-oauth-json-web-token-19 (http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-19) tools.ietf.org/html/draft-ietf-jose-json-web-signature-26 (http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-26)
  8. Macaroons: Overview Developed by Google Research team Provides for a

    simple distributed bearer token with - Delegation - Contextual Caveats
  9. Macaroons: Delegation Support for third-party authentication methods Flexible authorization (constrain

    access at the identity, resources) Credentials can be further constrained outside of originating service
  10. Macaroons: Contextual Caveats Attenuation / constraint of original macaroon using

    caveats Two types of caveats: first-party and third-party First-party is the originating service that creates the credential Third-party are any trusted external services that can validate credentials We will only be discussing first-party
  11. Macaroons: Implementations libmacaroons is available today for Debian/Ubuntu Python and

    Go bindings included github.com/rescrv/libmacaroons (https://github.com/rescrv/libmacaroons)
  12. libmacaroons: Installation #run as root/sudo wget -O - http://ubuntu.hyperdex.org/hyperdex.gpg.key |

    apt-key add - wget -O /etc/apt/sources.list.d/hyperdex.list http://ubuntu.hyperdex.org/trusty.list apt-get update apt-get install python-macaroons Run
  13. libmacaroons: attributes of a basic macaroon import macaroons # a

    basic macaroon consists of three elements # 1) the secret key known only to the credential authority (a web service or software) secret = 'kopdar_python_rocks' # # 2) some interesting metadata about this macaroon (can be anything) public = 'kopdar_members_only' # # 3) a URI/URL, possibly referencing a targeted web service (again, can be anything) location = 'http://www.python.or.id/' # Run
  14. libmacaroons: instantiating our macaroon # with these three arguments, we

    can now create the macaroon servis_kopdar = macaroons.create(location, secret, public) # # we now hold a reference to our newly instantiated macaroon object print(servis_kopdar) # we can inspect the HMAC signature of this message print('.signature: %s' % servis_kopdar.signature) # # or the other public metadata, like identifier or location print('.identifier: %s' % servis_kopdar.identifier) # print('.location: %s' % servis_kopdar.location) # # or all the metadata + signature in a single call print('.inspect():') print servis_kopdar.inspect() # # finally, we can convert the macaroon object to a serialized form for transport print '.serialize(): %s' % servis_kopdar.serialize() # Run
  15. libmacaroons: deserializing a macaroon import macaroons # token = "MDAyNmxvY2F0aW9uIGh0dHA6Ly93d3cucHl0aG9uLm9yLmlkLwowMDIzaWRlbnRpZmllciBrb3BkYXJfbWVtYmVyc19vbmx5CjAw

    # first, we attempt to rehydrate a valid macaroon instance from the string # try: print('Token to be deserialized: %s' % token) submitted_macaroon = macaroons.deserialize(token) # # we can check its details print('submitted_macaroon.inspect():') print(submitted_macaroon.inspect()) except macaroons.MacaroonError: print('The token provided is not a valid macaroon: %s' % token) except: print 'An unknown error occurred while deserializing the token' Run
  16. libmacaroons: validating the macaroon import macaroons # validation occurs using

    a Verifier object v = macaroons.Verifier() # # we'll need the original secret we created earlier secret = 'kopdar_python_rocks' # # secret = 'kopdar_python_is_ok-lah' # we attempt to verify the submitted macaroon print "Is the secret '%s'? -- %s" % (secret, v.verify(submitted_macaroon, secret)) # Run
  17. libmacaroons: adding user-specific constraints Our first macaroon was too general,

    so we need to provide our users with constrained credentials Notice that we do not need the secret to add constraints to a macaroon print servis_kopdar.inspect() # the original/base macaroon for the web service user_id = 'shirkey' # // the user's id HL password = '123456' # // the user's password # helper function for generating user-constrained macaroon def get_user_macaroon(userid): # notice that we can add constraints to a macaroon without providing the original secret! macaroon = servis_kopdar.add_first_party_caveat('userid=%s' % userid) # return macaroon # validate the user via authentication methods if some_authentication_method(user_id,password): user_macaroon = get_user_macaroon(user_id) # user_macaroon = user_macaroon.add_first_party_caveat('groupid=kopdar-python') print "Our new macaroon: \n", user_macaroon.inspect() # Run
  18. libmacaroons: validate user-specific constraints We will validate the user against

    a requested resource import macaroons servis_kopdar_token = 'MDAyNmxvY2F0aW9uIGh0dHA6Ly93d3cucHl0aG9uLm9yLmlkLwowMDIzaWRlbnRpZmllciBrb3BkYXJfbWVtYmVyc19v client_token = 'MDAyNmxvY2F0aW9uIGh0dHA6Ly93d3cucHl0aG9uLm9yLmlkLwowMDIzaWRlbnRpZmllciBrb3BkYXJfbWVtYmVyc19vbmx5CjA def get_access_to_user_resource_path(user_macaroon, resource_path): # first, we establish our Verifier as before v = macaroons.Verifier() v.satisfy_exact('userid=%s' % resource_path) return v.verify(user_macaroon, get_secret()) client_macaroon = macaroons.deserialize(client_token) # user macaroon requested_path = 'shirkey' # user has requested path = shirkey print('Can access user resource path at %s? %s' % (requested_path, get_access_to_user_resource_path(client_macaroon Run
  19. libmacaroons: validate user-specific constraints -- gotchas Notice that without the

    first-party caveat, our base macaroon can access any user resource import macaroons servis_kopdar_token = 'MDAyNmxvY2F0aW9uIGh0dHA6Ly93d3cucHl0aG9uLm9yLmlkLwowMDIzaWRlbnRpZmllciBrb3BkYXJfbWVtYmVyc19v client_token = 'MDAyNmxvY2F0aW9uIGh0dHA6Ly93d3cucHl0aG9uLm9yLmlkLwowMDIzaWRlbnRpZmllciBrb3BkYXJfbWVtYmVyc19vbmx5CjA def get_access_to_user_resource_path(user_macaroon, resource_path): # first, we establish our Verifier as before v = macaroons.Verifier() v.satisfy_exact('userid=%s' % resource_path) return v.verify(user_macaroon, get_secret()) client_macaroon = macaroons.deserialize(client_token) # user macaroon requested_path = 'shirkey' # user has requested path = shirkey print('Can access user resource path at %s? %s' % (requested_path, get_access_to_user_resource_path(client_macaroon Run
  20. libmacaroons: user can further constrain macaroon for delegation # user

    can take the original token provided by the web service, # and apply additional constraints to it client_macaroon = macaroons.deserialize(client_token) # timeout = datetime.now().date() # new_macaroon = client_macaroon.add_first_party_caveat('date=%s' % timeout) # print 'newly constrained macaroon:\n', new_macaroon.inspect() # this new token can now be delegated to another user for limited against the service delegation_token = new_macaroon.serialize() Run
  21. libmacaroons: now the token can be validated in delegated use

    # servis_kopdar obtains token from third party (not original client) print delegation_token asserting_macaroon = macaroons.deserialize(delegation_token) print 'Asserting macaroon: \n', asserting_macaroon.inspect() # the web service must support constraint checking for the specified caveat # so let's add a check for this constraint def get_access_to_user_resource_path(user_macaroon, resource_path): # first, we establish our Verifier as before v = macaroons.Verifier() v.satisfy_exact('userid=%s' % resource_path) v.satisfy_exact('date=%s' % datetime.now().date()) # return v.verify(user_macaroon, get_secret()) print "Is the user authorized to this resource? %s" % \ get_access_to_user_resource_path(asserting_macaroon, path) Run
  22. libmacaroons: further functionality satisfy_general -- create more complex verifications beyond

    string matching add_third_party_caveat -- include external verification of macaroons since Macaroons are based on HMAC, it is very likely we will see native Javascript implementations soon
  23. References Macaroons are Better Than Cookies! (article) (http://hackingdistributed.com/2014/05/16/macaroons-are-better-than-cookies/) My First

    Macaroon: A New Way to do Authorization (article) (http://hackingdistributed.com/2014/05/21/my-first- macaroon/) libmacaroons (source code) (http://github.com/rescrv/libmacaroons) Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud (the original research paper) (http://theory.stanford.edu/~ataly/Papers/macaroons.pdf) Macaroons: Cookies with Contextual Caveats for Decentralized Authorization in the Cloud (presentation by Google Research team member) (http://air.mozilla.org/macaroons-cookies-with-contextual- caveats-for-decentralized-authorization-in-the-cloud/) Cryptographic Security of Macaroon Authorization Credentials (additional research paper) (http://cs.nyu.edu/web/Research/TechReports/TR2013-962/TR2013-962.pdf)