samples icon indicating copy to clipboard operation
samples copied to clipboard

[Question] Security Concerns with Email Invitation Policy

Open andnorxor opened this issue 10 months ago • 4 comments
trafficstars

I'm no security researcher, but the policy provided for email invitation https://github.com/azure-ad-b2c/samples/blob/master/policies/invite-via-email/policy/GenerateInviteToken.xml

... relies on the following for security:

  • Knowledge of the client ID: The attacker needs to know the client ID of an application in Azure AD B2C (which is a UUID v4).
  • Knowledge of the policy's /authorize endpoint (optional): This can be determined if the sample is copied as-is without modification.
  • Nonce validation (optional): While this offers additional protection, it's only effective if properly validated at the redeem invite endpoint.

Although the design appears to seem secure enough in the best-case scenario (e.g., with a different policy name and proper nonce validation), for the worst case scenario relying primarily on the UUID of an application for security feels insufficient. UUIDs are not intended to serve as secure secrets, and this design may leave the invitation process vulnerable to exploitation if the UUID is exposed (by just asking for it) or guessed.

If my conclusions are correct, I would at least suggest enhancing the README to include

  • Clear guidance on how to implement stronger security measures (e.g., use of additional secrets or more robust validation mechanisms, firewall rules, validation of the redirect_uri).
  • Explicit recommendations for modifying policy names and enforcing nonce validation to minimize the risk of abuse.

andnorxor avatar Jan 04 '25 19:01 andnorxor

The policy generates a link with a signed JWT appended to it, id_token_hint query parameter.

Only you have the private key to generate this JWT.

The trust is then left to the users email provider being uncompromised.

A user can’t just generate the link using a client id. They need to compromise your private key to create a JWT that is appended to the link too.

If you think the link itself maybe hi jacked, then you could ask the user to perform some action in the redemption journey to prove they are who they say they are. For example, have them create a pin in the generate journey and have them type that pin at redemption.

jasjeetsuri avatar Jan 05 '25 21:01 jasjeetsuri

@jasjeetsuri Just to clarify: I'm not referring to the security of the JWT itself I'm referring to the endpoint exposed by the Azure B2C custom policy B2C_1A_INV_genlink which in the provided example is exposed to the public without any authentication.

This is the endpoint I'm referring to. It accepts some query parameters and generates a token without any authentication.

string url = string.Format("https://{0}/{1}/B2C_1A_INV_genlink/oauth2/v2.0/authorize?client_id={2}&nonce={3}" 
                    + "&redirect_uri={4}&scope=openid&response_type=id_token&disable_cache=true&login_hint={5}&displayName={6}"
                     , hostName, tenantName, clientId, nonce, redirectUri, email, displayName );

https://github.com/azure-ad-b2c/samples/blob/d6d5e2118174dc8e5bdc0ab1b0b125c3d6dfe060/policies/invite-via-email/source-code/run.csx#L40C9-L42C97

In contrast the example in https://github.com/azure-ad-b2c/samples/blob/master/policies/invite/README.md accepts a signed JWT as input, which is way better.

andnorxor avatar Jan 06 '25 09:01 andnorxor

Got it. The actual reason for this sample is for admins who want to use a link to verify an email instead of an email OTP that the user must type out. Hence the lack of auth on the generate journey, it is serving its purpose of self service sign up.

The samples are atomic, so you can combine any of them as you create something that best suits your needs.

jasjeetsuri avatar Jan 06 '25 09:01 jasjeetsuri

Thank you for the clarification. It seems this is a different use case then. My confusion stemmed from concerns about the potential lack of security mechanisms. And I've just discovered the other example now.

Perhaps this could be highlighted in the README, though that's just a suggestion. From my side, this issue can be considered resolved and closed.

andnorxor avatar Jan 06 '25 09:01 andnorxor