Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FedCM: unable to serve 'well-known file' on eTLD+1 within development environment #189

Closed
dusekjan opened this issue Nov 22, 2023 · 16 comments

Comments

@dusekjan
Copy link

Hello,
We as IdP are trying to integrate FedCM, our production domain has this pattern https://login.idp.com/ - I understand that well-known file must then be served from eTLD+1 so the URL would be https://idp.com/.well-known/web-identity.

But within the development environment our domains have this pattern https://login.dev.idp.com/ (dev.idp.com being a private DNS, not publicly accessible) and because dev.idp.com is not registered in the eTLD list (Public Suffix List) we are unable to properly test or implement FedCM. I guess the navigator requests a well-known file at https://idp.com/.well-known/web-identity.

We need the browser to send requests to https://login.dev.idp.com/.well-known/web-identity. How do we do that? Is there any special flag or configuration we can use in the dev environment to satisfy the condition:

well known file must be served from /.well-known/web-identity eTLD+1 IdP.

The #fedcm-without-well-known-enforcement flag does not work because the error is The fetch of the well-known file resulted in a network error: ERR_NAME_NOT_RESOLVED and not that the returned URLs providing the configuration files do not match.

@npm1
Copy link

npm1 commented Nov 22, 2023

If we changed the flag to skip fetching the well-known altogether, it could be in Canary within a couple of days. Would that work for testing purposes? Note that you'd need to use Chrome Canary as it would take some time for the change to reach the Stable channel. You would still be required to add the well-known file to the eTLD+1 root at some point before you can deploy to production and real users. Is this something you can do if you decide to deploy FedCM?

@yi-gu
Copy link

yi-gu commented Nov 22, 2023

In the interim, you could simply add a fake provider URL to the well-known file to avoid exposing your dev url. e.g.

// https://idp.com/.well-known/web-identity

{
  "provider_urls": [
    "https://idp.com"
  ]
}

When #fedcm-without-well-known-enforcement is enabled, we'd skip matching the configURL with provider_urls.

@ondras
Copy link

ondras commented Nov 22, 2023

(replying from the very same company as @dusekjan )

If we changed the flag to skip fetching the well-known altogether, it could be in Canary within a couple of days. Would that work for testing purposes?

Yeah, that would be great. Appreciated!

Is this something you can do if you decide to deploy FedCM?

We can. It implies a rather nontrivial amount of both paperwork and implementation work; I am somewhat curious about the real motivation behind this restriction (i.e. why is it forced to publish the .well-known at eTLD+1, when compared to other well-knowns we are already publishing - for instance, our login.idp.com/.well-known/change-password seems to work fine so far).

@dusekjan
Copy link
Author

If we changed the flag to skip fetching the well-known altogether, it could be in Canary within a couple of days. Would that work for testing purposes?

Like my colleague said, it would be really useful for us. Thank you!

@npm1
Copy link

npm1 commented Nov 23, 2023

The reason for having the well-known in the eTLD+1 is to ensure that the IdP can only have one such file, which provides some privacy guarantees like the config URL not containing any user data. If we allowed it to be in any folder, an IdP could have an arbitary amount of these and the privacy guarantee is lost. I do not believe this is needed for other well-known files such as change-password.

@ondras
Copy link

ondras commented Nov 23, 2023

The reason for having the well-known in the eTLD+1 is to ensure that the IdP can only have one such file, which provides some privacy guarantees like the config URL not containing any user data. If we allowed it to be in any folder, an IdP could have an arbitary amount of these and the privacy guarantee is lost

Thanks for the reply. It is still beyond my understanding what is the goal here; what kind of attack is this scheme trying to prevent. Is it somehow related to fedidcg/FedCM#230 ? (I am having a hard time understanding that vector as well.)

And I am pretty certain that other IdPs would be interested in understanding as well, yet the FedCM explainer does not seem to actually explain the motivation. May I ask for improving the documentation with respect to the discussed requirement?

In particular, could you explain the theoretical attack/privacy-denial vector that would be possible if the IdP hosted the well-known file in multiple locations? The RP is obviously free to pick any of these multiple locations... as long as they are documented and they provide the relevant FedCM endpoints/services.

@yi-gu
Copy link

yi-gu commented Nov 23, 2023

The goal is that the IdP should NOT learn about the RP and user credential at the same time before user permission. i.e. in the accounts_endpoint where IdP gets user credential, they should NOT know which RP the user is visiting.

The IdP (attacker in this case) could start with the following API call on the website https://rp.example:

navigator.credentials.get({
  identity: {
    providers: [{
      "configURL": "https://idp.example/${window.location.href},
      "clientId": "1234"
    }]
  }
});

The IdP can then joint the RP information with user information in the manifest https://idp.example/*rp*/fedcm.json like the following:

{
  "accounts_endpoint": "${rp}/accounts.php",
  "id_assertion_endpoint": …
}

@npm1
Copy link

npm1 commented Nov 23, 2023

By the way, feel free to go over the spec since we did try to capture most of our privacy and security considerations there. For the well-known in particular, see https://fedidcg.github.io/FedCM/#manifest-fingerprinting

@ondras
Copy link

ondras commented Nov 23, 2023

The goal is that the IdP should NOT learn about the RP and user credential at the same time before user permission

I understand that it is desirable for the IdP to NOT know about a particular RP before the assertion call is performed. While I do not see the immediate risk of revealing the RP to IdP (is there any, really? in oauth-based scenarios, providing client_id to IdP is the very first thing that happens), I am okay with IdP not knowing RP's identity.

The IdP (attacker in this case) could start with the following API call on the website https://rp.example:

Now this is an interesting formulation. Even if we assume that IdP is an attacker, how can this IdP influence/modify/adjust the code that is presented on RP's webpage? I was working under the assumption that IdP and RPs are independent entities, different companies etc. We are going to provide our IdP services to multiple RPs, but we cannot control the contents of their respective pages. How could a malicious IdP cause the RP (victim?) to put this anonymity-breaking configURL definition in their page?

To sum my questions up:

  1. why is the IdP forbidden from knowing the RP identity in advance? I understand that this information reveals the fact that the user is visiting RP, but this is done on RP's explicit behalf (via the credentials.get call).

  2. how/why would a privacy-aware RP put their own identification in the configURL, revealing themselves to a malicious IdP?

@ondras
Copy link

ondras commented Nov 23, 2023

Update: it appears that some (all?) of my concerns seem to be somewhat rectified in https://fedidcg.github.io/FedCM/#attack-scenarios (one section above the originally linked spec content).

Just to make sure I understand correctly: we are discussing a scenario where both RP and IdP are cooperating together, not really trying to use FedCM to provide sign-in, but rather abusing the FedCM functionality to allow tracking visits between RP and IdP (or multiple different RPs), right?

I am still somewhat puzzled about this scenario, as FedCM is obviously based on user interaction an browser-provided UI, so it is unclear to me how would the abuse happen without the user being presented with explicit (fake) sign-in choices.

@npm1
Copy link

npm1 commented Nov 23, 2023

  1. To clarify, it is fine for IdP to know that RP wants to use federation. In fact, the client metadata fetch passes the RP along with its client ID. But it is not fine for IdP to know that the user wants to use federation on this RP. If the credentialed fetch to the accounts endpoint was allowed to include the RP, that would be an unwanted leak.
  2. That is not the browser's threat model perspective. The RP and IdP should not be allowed to collude to allow cross-site tracking via the user's IdP identity. So yea, an RP could prevent get() from passing parameters that the IdP does not need to know about, but it could also not prevent it.
  3. RP and IdP colluding doesn't mean that the user has not signed in to the IdP. They may have accounts in the IdP, so the UI will not necessarily show 'fake accounts'.

@ondras
Copy link

ondras commented Nov 23, 2023

But it is not fine for IdP to know that the user wants to use federation on this RP.

I would say that the assertion call is giving IdP precisely this kind of information? Both the RP identity (client_id) and user identity (cookies) are sent with the assertion call, so the IdP then knows that the user wants to use federation.

3. They may have accounts in the IdP, so the UI will not necessarily show 'fake accounts'.

That is true. But the RP (still thinking about the criminal scenario with colluding RP and IdP) has two choices:

  • A. Ignore the resulting FedCM secret, so that the next visit will call get() again to perform tracking. This will present the user with FedCM UI every time this malicious RP is visited, considerably lowering their credibility.
  • B. Finish the FedCM interaction by storing the received secret and using it to identify the user during following visits; this will imply no more get() calls, so no more tracking via IdP.

I would say that both of these variants are not suitable for a malicious RP, thus a malicious RP cannot systematically/successfully abuse FedCM to perform reliable tracking.

@npm1
Copy link

npm1 commented Nov 23, 2023

I would say that the assertion call is giving IdP precisely this kind of information? Both the RP identity (client_id) and user identity (cookies) are sent with the assertion call, so the IdP then knows that the user wants to use federation.

Id assertion is only fetched after user chooses to perform federation. So yes of course we are ok with the IdP knowing this, once the user has gone through the flow.

That is true. But the RP (still thinking about the criminal scenario with colluding RP and IdP) has two choices:

  • A. Ignore the resulting FedCM secret, so that the next visit will call get() again to perform tracking. This will present the user with FedCM UI every time this malicious RP is visited, considerably lowering their credibility.
  • B. Finish the FedCM interaction by storing the received secret and using it to identify the user during following visits; this will imply no more get() calls, so no more tracking via IdP.

I would say that both of these variants are not suitable for a malicious RP, thus a malicious RP cannot systematically/successfully abuse FedCM to perform reliable tracking.

If the eTLD+1 requirement was removed, the malicious RP can use their owned eTLD+1 to use a different origin every time, so no UI is ever shown. They would always just say that there are no accounts.

@ondras
Copy link

ondras commented Nov 23, 2023

If the eTLD+1 requirement was removed, the malicious RP can use their owned eTLD+1 to use a different origin every time, so no UI is ever shown. They would always just say that there are no accounts.

I see. Well, I think I have no more questions now - all answered. Thanks a lot for you time and patience!

@yi-gu
Copy link

yi-gu commented Nov 23, 2023

Good news, the change is landed in 121.0.6144.0. It should be in Canary for some users now. If you don't get it today, it should be tomorrow.

@dusekjan
Copy link
Author

Good news, the change is landed in 121.0.6144.0. It should be in Canary for some users now. If you don't get it today, it should be tomorrow.

Great! It works as I expected. Thank you very much for your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants