Project – Certified OpenID Connect & OAuth 2.0 Engine for ASP.NET Core – https://identityserver.io • Co-Creator of PolicyServer – Authorization for modern Applications – https://policyserver.io • Co-Founder of Duende Software – the new home of IdentityServer – https://duendesoftware.com email dbaier@leastprivilege.com blog https://leastprivilege.com twitter @leastprivilege slides https://speakerdeck.com/leastprivilege
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/html/rfc8725 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/
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)
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
• 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
+ various BCPs == OAuth 2.1 – https://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2-1/ • Most important changes – omission of implicit grant – omission of password grant – PKCE must be used with the authorization code grant – redirect URIs must be compared using exact string matching – refresh tokens must be either sender-constrained or one-time use only – bearer tokens usage omits token in the query string
to rotate keys regularly – must keep a history of old keys (depending on max access token lifetime) • Algorithms – OIDC mandates RS256 as a minimum – OpenBanking/PSD2 requires PS256 – FHIR requires EC-based algorithms
– identifies the principal that issued the JWT • sub (Subject) – identifies the principal that is the subject of the JWT • aud (Audience) – identifies the recipients that the JWT is intended for • exp (Expiration Time) – identifies the expiration time on or after which the JWT MUST NOT be accepted for processing • nbf (Not Before) – identifies the time before which the JWT MUST NOT be accepted for processing • iat (Issued At) – identifies the time at which the JWT was issued • jti (JWT ID) – provides a unique identifier for the JWT https://tools.ietf.org/html/rfc7519#section-4.1
a standard, every vendor came up with different claims and semantics – how to convey user and client ID – define additonal claims – nbf vs iat – scopes vs audiences – required vs optional – cross-JWT confusion and substitution attacks • Two specs aim to provide interoperable definitions – https://tools.ietf.org/html/rfc8725 – https://datatracker.ietf.org/doc/html/draft-ietf-oauth-access-token-jwt
ID • sub – if user is present: sub as defined in OpenID Connect – if no user is present: OAuth client ID https://datatracker.ietf.org/doc/html/draft-ietf-oauth-access-token-jwt#section-2.2
principal that issued the JWT • exp – identifies the expiration time on or after which the JWT MUST NOT be accepted for processing • aud – identifies the recipient(s) that the JWT is intended for • iat – identifies the time at which the JWT was issued • jti – provides a unique identifier for the JWT
to indicate "what" the clients wants to access The authorization and token endpoints allow the client to specify the scope of the access request using the "scope" request parameter. The value of the scope parameter is expressed as a list of space-delimited, case- sensitive strings. If the value contains multiple space-delimited strings, their order does not matter, and each string adds an additional access range to the requested scope. The authorization server MAY fully or partially ignore the scope requested by the client, based on the authorization server policy or the resource owner's instructions. RFC6749
re-used at multiple resources – makes tokens very powerful • in case of leakage – prohibits resource-specific processing • e.g. token content, encryption – concerns about token re-use • especially with absence of sender constraints • Can't prohibit that clients requests token that can be used at multiple resources
parameter – resource • Indicates target service or resource to which access is being requested – must be an absolute URI – might be a physical network address – multiple resource parameters are allowed
more resource – can be combined with scope GET /as/authorize? client_id=client& response_type=code& state=xyz& redirect_uri=https://client/cb& resource=https://invoice.api.com& resource=https://customer.api.com 1
must be specified – returned token is for the requested resource only POST /as/token grant_type=authorization_code& redirect_uri=https//client/cb& code=abc& resource=https://invoice.api.com { "access_token":"ey…Yw", "token_type":"Bearer", "expires_in":3600, "refresh_token":"4L…C2" } 2 { "iss": "http://as.com", "aud": "https://invoice.api.com" "iat": 1588420700 "exp": 1588420800, "sub": "123", "client_id": "456" }
authorization parameters as a JSON Web Token – signed for integrity and client authentication – encrypted for confidentiality • Mitigates several known attacks – redirection URI re-writing – mix-up attacks https://tools.ietf.org/html/draft-ietf-oauth-jwsreq
Provides interoperable endpoint to push authorization request parameters – in exchange for a request_uri – allows for authentication for confidential clients – manages entropy and lifetime https://tools.ietf.org/html/draft-ietf-oauth-par
OAuth 2.0 spec – only bearer tokens were specified • Several attempts to introduce PoP at the application layer – required a lot of application layer crypto (e.g. signing of HTTP requests) – some unsolved problems (e.g. streaming) • ...then at the transport layer – HTTP token binding (deprecated)
name) { var distinguishedName = new X500DistinguishedName($"CN={name}"); using (var rsa = RSA.Create(2048)) { var request = new CertificateRequest( distinguishedName, rsa, HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1); request.CertificateExtensions.Add( new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false)); request.CertificateExtensions.Add( new X509EnhancedKeyUsageExtension( new OidCollection { new Oid("1.3.6.1.5.5.7.3.2") }, false)); return request.CreateSelfSigned( new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(10))); } }
Proof-of-Possession at the Application Layer (DPoP) An application-level sender-constraining for access and refresh tokens that can be used in cases where MTLS is not available. It uses proof-of- possession based on a public/private key pair and application-level signing. DPoP can be used with public clients and, in case of confidential clients, can be combined with any client authentication method. https://tools.ietf.org/html/draft-fett-oauth-dpop
public key as confirmation method { "iss": "https://server.example.com", "client_id": "client1", "exp": 1493726400, "cnf": { "jkt":"0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I" } } Base64url encoding of the JWK SHA-256 Thumbprint of the public key (RFC 7638) https://tools.ietf.org/html/rfc7638
– wraps up several guidance documents – removes protocol flows that turned out to be problematic • Additional specs strengthen OAuth security – JAR & PAR – Resource Indicators – PoP