Background
This document covers the required properties for shared identifiers that are used in integrations between Google and a Vendor (or Issuer of the account to the user). A good way to think about a shared identifier is that it is an opaque pointer to an edge between a Google account and an Issuer account.
Therefore, it's important to remember that the shared identifier does not refer to either the Google account (or user or other entity in Google’s storage) nor the Vendor/Issuer Account (or other entity). It refers to the link between these two.
Shared Identifier Properties
The properties that are required of shared identifiers are born from past experience and technical issues that have been encountered as a result of the lack of these properties in shared identifiers.
For an integration between Google and an external partner, it is critical that the shared identifiers used have the following properties:
- Be Globally Unique: this shared identifier must point to exactly one link between a Google user and an Issuer account. There must not be another shared identifier for the same Issuer that has the same value.
- Be Unguessable: These shared identifiers carry permission to take action on behalf of the user, so it is important that it is not possible for a third party to be able to guess the shared identifier value.
- Be Revocable: It is important that a shared identifier may be revoked by the user
and this revocation should prohibit any future use of the shared identifier value.
This property has a few corollary properties that follows:
- Not based on an immutable property of either account: If the shared identifier value were to be based on an immutable property of either the Issuer’s account or the Google account, then a recreation of a revoked shared identifier would result in the same value of that shared identifier (thereby undoing the revocation), so the shared identifier’s value must not be a property of the account (e.g. should not be a phone number or a hash of a phone number).
- Not be merely <Google Account, Partner Account>: there must be some other value (e.g. time) to allow revocation.
- Allow multiple links for the account on either side: It is important that
the shared identifier value creation does not make it impossible for a single Google user
to link to multiple bank accounts or for more than one Google account to link
to a single bank account (e.g. a parent and a child account that are both
linked to the parent’s bank account). Similar to revocability, this has a
few corollaries:
- Again, not based on an immutable property of either account: Otherwise the shared identifier would have the same value when single Google user linked multiple bank accounts (if the shared identifier value were based on the Google account) or if multiple Google accounts are linked with a single bank account (if the shared identifier value were based on a property of the bank account)
- Be Long-lived: The shared identifier is only valid in a secure context (the integration between Google and the vendor, which uses both connection-level and application-level protections (e.g. PGP, mutual SSL, etc), so it doesn't need a short life cycles to remain secure. Google’s preference is that the shared identifiers never expire, but if a vendor requires expiry, it must be a long time period (e.g. >1 year).
Other shared identifier properties that are recommend are the following:
- Base64: this makes transport and communicating the value in the integration easy over https.
- Minimum Length: A minimum of 27 digits (before Base64 encoding) is recommended to ensure that there is plenty of address space to avoid collisions.
What Can Go Wrong?
To help the reader understand the properties that are required, these are a few case studies that illustrate the problems encountered when these properties are not adhered to.
Shared Identifier Case Studies
Case Study #1: Phone Number Recycling
An issuer that used the user's phone number as their shared identifier. When User A changed phone plans, they gave up their phone number and got a new one. A month later, the phone company recycled the old phone number and suddenly the phone number's new owner, User B, started seeing charges against their account for things they weren't buying.
The issuer had violated many shared identifier properties, mainly property #1. Things like phone numbers can migrate from user to user, so they are only unique during a particular snapshot in time.
Case Study #2: The Paste
A Google/Partner employee accidentally pastes a shared identifier into a chat instead of an internal tool. Additional layers of protection prevent anyone from maliciously using the shared identifier, but to be safe Google wanted to revoke the shared identifier and replace it with a new one. When Google/Partner try to revoke the shared identifier, they find that the shared identifiers are just the user's account ID in the Issuer's system and the shared identifier is used to directly look up the user's account. Therefore the shared identifier couldn’t be revoked without deleting the user's account and creating a new one for them.
Case Study #3: The Bad Employee
After "The Paste" incident above, a bad actor within Google/Partner realizes that since the shared identifier is just the user's account ID, if they can manage to put someone else's account ID into their own shared identifier value, they can make purchases against that other person's account. The violation of Property #2 has made this inadvertent paste more than a security hole for a single user -- it is a security hole for every user.
Case Study #4: The Rotation
After "The Paste" incident above, the Issuer switches to a UUID as their shared identifier format. This time, an Issuer employee mistakenly emails out some of the shared identifiers in plaintext as part of a debugging email thread. Google says, no worries we'll just revoke and replace the user's shared identifiers.
As part of the rotation, Google tells the Issuer that each compromised user account will have two shared identifiers active for a short period of time while database clean up is going on. But the Issuer has not allowed for Property #4 and tells Google that they have a constraint that only one shared identifier can be active for a particular user account. This leads to a very messy rotation with race conditions.