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 Engine for ASP.NET Core – 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
+ various BCPs == OAuth 2.1 – https://tools.ietf.org/html/draft-parecki-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
typically coarse grained – some implementations use custom structured format, e.g. transaction:id • RAR introduces new authorization_detail parameter – "allow client to make a payment of 45€" – "allow client to read folder X, and write file Y" • Outcome of decision can be used to restrict access token to certain action(s) – typically combined with consent https://tools.ietf.org/html/draft-ietf-oauth-rar
], "actions": [ "read" ], "datatypes": [ "contacts" ] }, { "type": "customer_images", "locations": [ "https://example.com/images" ], "actions": [ "print" ], "datatypes": [ "photos" ], "identifier": "1" } ] represents the kinds of data being requested from the resource A string identifier indicating a specific resource available at the API schema
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
– replaces scope • JAR allows for signed, authenticated authorization requests – also encrypted if needed – also allows transmitting additional (trusted) data • PAR provides endpoint to push authorization request – removes all data from front-channel
keys – AS does not need to store any secret (only the public key) – secret not exposed over the wire • private_key_jwt – https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication – https://tools.ietf.org/html/rfc7523 • Mutual TLS – https://tools.ietf.org/html/rfc8705
it with its private key – can add additional custom claims Claim Description iss must contain the client ID of the OAuth client sub must contain the client ID of the OAuth client aud identifies the AS, e.g. URL of token endpoint or issuer name jti unique identifier for the token, which can be used to prevent reuse of the token exp expiration time of JWT iat time at which the jwt was issued (optional)
credential, string clientId, string audience) { var now = DateTime.UtcNow; var token = new JwtSecurityToken( clientId, audience, new List<Claim>() { new Claim(JwtClaimTypes.JwtId, Guid.NewGuid().ToString()), new Claim(JwtClaimTypes.Subject, clientId), new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64) }, now, now.AddMinutes(1), credential ); var tokenHandler = new JwtSecurityTokenHandler(); return tokenHandler.WriteToken(token); }
and validator • Adds replay cache based on IDistributedCache – can be replaced var builder = services.AddIdentityServer() .AddJwtBearerClientAuthentication();
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)
Mutual-TLS Client Authentication and Certificate-Bound Access Tokens – https://tools.ietf.org/html/rfc8705 • Covers both authentication and Proof-of-Possession
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))); } }
– supports path-based endpoints – PKI method only • Azure – supports path-based endpoints (but only via exclusion paths) • Kestrel – does not support any isolation • Nginx – supports domain/sub-domain isolation – supports PKI and self-signed
server needs similar setup – accept/validate client certificates – forwarding of certificates to application host • After normal access token validation – compare certificate thumbprint of TLS channel with cnf claim in access token – if they match, caller can prove that it has access to the same key material • proof-of-possession
and secure than shared secrets • Private key JWT – allows securing both front- and back-channel with single key pair • TLS client certificates – allows binding access token to client – even for public clients