Verify those emails
Here’s an interesting escalation attack against Azure AD, a commonly used Identity Provider from June, 2023. The tl;dr is that:
… use of the email claim from access tokens for authorization can lead to an escalation of privilege [and an] attacker can falsify the email claim in tokens issued to applications.
An email claim in a token issued by your IdP might be part of your authorization strategy. For instance, you might take the email claim and pass it to another service to get data about that user, or discover permissions of the user.
With Azure AD, this breaks because in certain circumstances, the email can be spoofed. More guidance from Microsoft on mitigating this attack.
But even in a typical CIAM system where the email can’t be spoofed in this manner, if you don’t verify emails and rely on the email
claim in your tokens, you can be in trouble.
Here’s how that works if you allow users to register themselves in your system. (This assumes that there is data in a system for the email address user@example.com before user registration.)
An attacker registers user@example.com with a credential they control.
They log in with user@example.com and are issued a token with that value for the
email
claim.A system reads the token and looks up the data or permissions for that account. After all, the token is signed correctly.
The system returns the data.
Attacker now has data they should not.
Contrast that with a flow where emails addresses are verified. First, the normal flow, for a regular user.
A user registers user@example.com with a credential they control.
They are sent an email with verification information (typically a link or a code).
They verify their ownership of their email inbox by clicking the link or providing the code.
They log in with user@example.com and are issued a token with that value for the
email
claim.A system reads the token and looks up the data or permissions for that account.
User gets access to their data.
Next, here is the flow for an attacker.
An attacker registers user@example.com with a credential they control.
An email is sent with verification information (typically a link or a code).
The attacker cannot verify the email address.
The attacker logs in.
The system checks for a verified email address and fails to find one.
The system stops them from proceeding.
So, in general, email verification is a good thing, especially if self-service registration is allowed.
If you are using OIDC, you can check the email_verified
standard claim. If the OIDC OpenID Provider is configured correctly, the value of claim can assure you that the user has possession of the inbox corresponding to the email. Consult the documentation of your OIDC system for more details.
Verifying an email is always a good idea. It introduces some friction, but, as you saw above, allows assurances about ownership of an email address.
But email addresses change, so a better choice in general is to use the sub
claim as a user identifier. This is an arbitrary string unique to the user within the OpenID Provider. When you use this claim, combined with the iss
claim which uniquely identifies the OpenID provider and which should be a value you expect, you have a stable user identifier.
From the specification:
The sub (subject) and iss (issuer) Claims, used together, are the only Claims that an RP can rely upon as a stable identifier for the End-User, since the sub Claim MUST be locally unique and never reassigned within the Issuer for a particular End-User, as described in Section 2. Therefore, the only guaranteed unique identifier for a given End-User is the combination of the iss Claim and the sub Claim.
In short, don’t use the email for any downstream user data lookup or permissions; instead prefer stable identifiers.
But if you must, make sure you verify the email, especially if you allow self-service registration as a provisioning strategy.
Dan