[edit: Caleb points out that I could be clearer in stating that using just the PPID for authenticating requests is truly a bad idea, and I have to agree. Language hardening in progress..]
In short: When you register users by using their information cards, storing the Unique ID is better than just saving the PPID. Actually, just resorting to the PPID is strongly discouraged.
And here it comes the explanation 🙂
You already know what is a PPID. A PPID, or Private Personal Identifier, is an ID that identifies a specific card for a certain relying party. In case of a self issued card, Cardspace itself calculates the PPID as a combination of the reying party certificate and something unique about the card. It is the only claim in a self issued card that is automatically calculated, as opposed to be provided by the card’s owner. The presence of the PPID claim can be required by a relying party by mentiong the URI “http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier” in the list of the mandatory claims.
A PPID is a very useful item: one card will always send different PPIDs to different relying parties, so that even if a hacker steals the PPID for RP A there’s no way that such PPID will useful also for RP B. It travel in an encrypted token, so that man in the middle attacks cannot access it. Finally, it is not shown in full in the UI so that social engineeering attacks in which the user is tricked into reading it out loud are not possible.
With all those good things about it, it’s not surprising that the PPID is used in so many cardspace examples as the information stored during new user’s sign up operations. During the registration process the website/webservice asks for a token containing the PPID: the user chooses one card, sends the corresponding token and saves the PPID in the user db. During returning visits, the user is once again asked to choose a card featuring the PPID claim: the website just compares the PPID with what was stored in the db, and if they match bingo! You’re in. That’s nice, and it’s definitely better than username and password. But it’s not as good as it can get.
In the end , a PPID is just a claim: it is not involved (directly) in cryptographic operations performed on (or with) the token. That usually means that until the PPID stays a secret we’re safe, but if something goes wrong we could have troubles. It is true that the PPID is protected from generation to transmission, but once it reaches the RP in form of claim it is as secure as the RP chooses to protect it. If somebody breaks on the user DB, or if a disgruntled employee decides to make some ID sweeping, if the tables are not properly encrypted the PPID can be acquired. At this point, our bad guy has all the means for signing in. If the RP does not mandate an issuer, for example, the bad guy can write his own STS and assign the stolen PPID to his own managed cards: if the RP checks just the claim value, it will accept it as a succesful sign in. If the RP mandates a selfissued card things are harder but still possible: in this case the bad guy will have to avoid using the cardspace UI and craft the token himself, taking care to embed the right claim.
Why is all this possible? Because we are just relying on a shared secret, the PPID: we take advantage of cryptographic operations just for keeping the token unreadable and unmodifiable by non-authorized, but we don’t really leverage it in the details of authentication. However, those operations DO take place: to name one, the token we receive will always be signed by the token issuer. That operation can be performed by the issuer and the issuer only, since it’s the sole owner of his private key: if during the user registration process we can somehow capture in a secure way the identity of the issuer, we would not be relying just on a shared secret anymore. To make the concept more concrete, consider an example in which, instead of saving just the PPID during the new user registration, we save a combination of the PPID and the public key of the token issuer.
In that case, during a returning visit we would chech the value of the claim AND the key that was used for signing the token itself: while the PPID can be acquired, as described above, the signature cannot be faked. The only way of signing in is obtaining a token from the issuer that was used during the registration, and in the case of self issued cards this means that only the use of the original card will grant access. 🙂
Note also that nothing prevents you from storing ALSO the PPID: that may come in handy if your user has troubles, since a sinmplified version fo the PPID is shown in the Cardspace UI and can be a useful moniker for support calls.
The good news is that the current examples on the community website makes it super easy for you to leverage the above. Garrett‘s TokenProcessor class demonstrates the use of the member UniqueID, which is exactly a combination of the PPID and cryptographic material associated with the token issuer. It even features a configuration plug that you can use for varying the claims from which the UniqueID gets constructed! And speaking of Garrett, we had various discussions on the subject: I believe he’ll sooner or later write a detailed post on the subject, as soon as he’ll do I’ll add the relevant link here.
So, it’s 1:37 AM and I better go to sleep: let’s summarize.
- Using PPIDs for saving user identities is more secure than passwords (not easily accessible to the user, all exchanges are intrinsically secured, guaranteed that it ill be used with only an RP, etc)
- Relying just on PPIDs means using a shared secret system, so there are few cases in which the mechanism can be subverted. Incidentally, those are among the same reasons for which using passwords is not a good idea: hence, I recommend staying away from it as the only key in your user store
- Using a combination of PPID and the cryptographic material involved in securing the token defuses the risks of PPID leaks described above
If you have questions, do not hesitate to drop me a line. If it’s not too clear, I will be happy to update the post with one of my signature diagrams 🙂