URLs on the Internet are case sensitive by definition. Some web servers choose to be case insensitive. To treat OpenID urls as anything but case sensitive for purposes of identifying a user introduces a grave security risk. Implementers of OpenID should be cautious when using case-insensitive string comparisons and be aware that in most cases checks should be case sensitive.
OpenID Claimed Identifiers
Consider the tale of three URLs:
- http://MYPROVIDER.org/myuser
- http://myprovider.org/myuser
- http://myprovider.org/MYUSER
If entered into an OpenID login box, which combination of these URLs are guaranteed to represent the same identifier and therefore the same person? (go ahead and think about it)...
If you decided all three, from an intuitive user perspective, you'd be right. But from a security perspective, only 1 and 2 should be recognized as the same. An RFC-abiding, self-respecting web server may be case sensitive for the path in its URL. Linux/Apache servers may be configured this way quite easily, perhaps even by default in some cases. Therefore an OP that does not take specific precautions to prevent multiple identifiers that differ only in casing from existing simultaneously would be open to the following attack:
- User A visits myprovider.org and acquires the myprovider.org/myuser identifier.
- User A visits somerp.com and logs in as myprovider.org/myuser.
- User B seeks to spoof User A's identity on somerp.com.
- User B visits myprovider.org and acquires the myprovider.org/MYUSER identifier.
- User B visits somerp.com and logs in as myprovider.org/MYUSER.
- somerp.com does a case insensitive comparison and considers User B to be the same person as User A. somerp.com grants all access that User A should get to User B.
Now, who broke a rule here? Although some might argue that myprovider.org is a poor Provider, it hasn't actually violated any RFCs or the OpenID spec. And since somerp.com has no way of knowing whether given Provider is case sensitive or not, to prevent the above identity spoofing scenario it MUST perform a case sensitive comparison.
Now the one exception to this is in the authority area of the URI. The authority is the hostname.myprovider.org area of the URL. The authority is case insensitive because DNS is case insensitive and the authority is not sent as part of the GET line in the HTTP protocol (it may be sent as one of the HTTP headers afterward, but no server can rightly be case sensitive on that particular header). So to be fully correct, safe, and as user-friendly as possible, the URL should be compared in two parts: the authority which would be case insensitive, and the path+query+fragment segment which would be case sensitive.
Realm-return_to validation
And if you're not yet convinced, consider the next concern regarding casing: realm-return_to validation. Part of an OP's responsibility is verifying that a return_to URL falls somewhere at or beneath the realm URL. There are security reasons for this validation that fall outside the scope of this post. But case sensitive testing here is also very important.
Consider this scenario:
- Shared hosting provider www.yourpages.com allows subscribers to host their own web sites as virtual app directories under their domain, such that one subscriber choose www.yourpages.com/user1/ as the root of their site and another subscriber might choose www.yourpages.com/user2/ as the root of their site.
- User 1 subscribes to www.yourpages.com and chooses to host his OP Provider site at www.yourpages.com/RadProvider.
- User 2 wants an OpenID URL and gets this one from RadProvider: www.yourpages.com/RadProvider/User2IsCoolGuy
- User 2 visits somerp.com and logs in with www.yourpages.com/RadProvider/User2IsCoolGuy and establishes private information with somerp.com.
- User 3 sets up his own OpenID Provider at www.yourpages.com/radprovider/. Notice he chose the name to match an existing provider but with different casing. This case sensitive shared hosting service didn't think of the security ramifications behind his innocent web server allowing multiple users to have such similar paths and so User 3 exploits this.
- Now consider an OpenID authentication request in which realm is www.yourpages.com/radprovider and the return_to url is www.yourpages.com/RadProvider. The RP discovery step, which is a very important security improvement in OpenID 2.0, is totally thwarted because it will be done on the wrong Provider site. Several authentication hacks can be done without RP discovery to thwart the security offered by OpenID.
Summary
Realm-return_to validation checks, and Claimed Identifier matching MUST be done in a case sensitive way for the path+query+fragment pieces, and SHOULD be case insensitive for the scheme and authority parts.
My argument here is not that this is common, but that it is possible. And possible is all it takes for a security hole to be exploited and people's identity to be compromised.
In a follow-up post, I will present what OPs can do to give their users a great user experience even if all the RPs are properly case sensitive, such that their users can enter their OpenID URLs in any case they like and still authenticate properly.
4 comments: