smart-on-fhir / health-cards

Health Cards Framework: implementation guide and supporting material
Other
261 stars 84 forks source link

It doesn't make sense to use /.well-known with a URL prefix that has a path component #157

Closed ekr closed 3 years ago

ekr commented 3 years ago

You are storing public keys at:

  <<iss value from JWS>> + /.well-known/jwks.json

Where the iss value isn't just a domain name but a full URL with a path component. You use the example:

https://smarthealth.cards/examples/issuer

Per RFC 8615, however, a well-known URIs have a path component that begins with /.well-known:

A well-known URI is a URI [RFC3986] whose path component begins with the characters "/.well-known/", provided that the scheme is explicitly defined to support well-known URIs.

For example, if an application registers the name 'example', the corresponding well-known URI on 'http://www.example.com/' would be 'http://www.example.com/.well-known/example'.

The reason for this is that well-known locations are about the origin [https://datatracker.ietf.org/doc/html/rfc8615#section-4.1], so having this kind of prefix doesn't make any sense, as the consumer of this is unable to determine the access controls on it.

Paging @mnot in case he wants to weigh in.

jmandel commented 3 years ago

Thanks for bringing this up here. Allowing for a path segment is consistent with the decision we made in the SMART App Launch v1 spec (http://hl7.org/fhir/smart-app-launch/conformance/index.html#using-well-known) -- but I agree that interpretation is more challenging.

In the Health Cards spec we might at least 1) call this out explicitly, and 2) recommend against inclusion of a path component.

ekr commented 3 years ago

OK, so I see the text in § 4, but I don't understand what the point of the /.well-known is in this instance. Given that whoever provided the URI controls the path, they could just as well supply the entire path including the /.well-known.

Moreover, from a security perspective, the point here is that the identity associated with the keys is not the origin, it's the entire URI path prefix. To give a concrete example, imagine I hosted keys at https://github.com/ekr/foo/.well-known. This doesn't reflect a statement by Github but rather by me, but there's no realistic way to know exactly what that means without understanding the structure of each individual origin's site. So, I don't think it's just a matter of recommending against inclusion but rather that you should forbid it and require rejection.

The Health Cards spec seems a bit unclear on precisely how one learns valid issuers, but imagine a design in which the verifying client is preconfigured with origins and then just verifies that the issuer URIs corresponded to one of those origins without checking the path component. That would clearly be insecure.

jmandel commented 3 years ago

but I don't understand what the point of the /.well-known is in this instance

It's purely a convention for ensuring that issuers can host key in a way/place that won't overlap with other paths in their server.

To give a concrete example, imagine I hosted keys at https://github.com/ekr/foo/.well-known. This doesn't reflect a statement by Github but rather by me, but there's no realistic way to know exactly what that means without understanding the structure of each individual origin's site.

This is correct. In some cases a given issuer's site structure can tell you more, but this is distinct from origin-binding. The trust assessment is at the level of the full URL (iss value).

The Health Cards spec seems a bit unclear on precisely how one learns valid issuers, but imagine a design in which the verifying client is preconfigured with origins and then just verifies that the issuer URIs corresponded to one of those origins without checking the path component. That would clearly be insecure.

The expectation is that a piece of verifier software can embed a list (or reference an external list) of iss URLs it trusts -- this is to say, URLs and not just origins.

lcmaas commented 3 years ago

The .well-known approach with a path is actually consistent with OpenID Connect, which requires deviation from the RFC when the issuer URI contains a path, such as to differentiate tenants in certain multi-tenant environments, retaining any path components. See OIDC Core.

As Josh notes, this is also retained in the SMART app launch framework for healthcare. Disallowing or even recommending against these established patterns is not a good idea IMO. Keys could (and ideally should) be different for different tenants, each signing the data that they are responsible for.

lcmaas commented 3 years ago

And to the point about whether to trust these keys not linked to the origin, that is addressed by issuing certificates linked to the actual service endpoint rather than the hostname. Generally, we should avoid relying on the Internet PKI to establish identity of a service operator, as this PKI is in most actual deployments at best suited to demonstrate control of a base domain only, not that the entity controlling the base domain is a health care organization or that it can be trusted.

jmandel commented 3 years ago

Given discussion above, will close this -- appreciate the close read, and agree with the point that this key binding approach can't be equated with origin-binding.