App Integration with Google OpenID Single-Sign-On
Our application is built on Python/Django and as a result, we looked to django-social-auth as a framework to provide OpenID authentication with the existing Django users account framework. django-social-auth itself relies on the python-openid library to handle the actual OpenID protocol implementation. One feature that django-social-auth provides is the ability to associate existing Django user accounts with new OpenID identifies if they share the same email address. This is great for our existing users that now want to be able to access their I Done This account via Google Apps or Chrome. But using email addresses as identities for account associating could be a security risk.
Implementation Vulnerabilities in Handling of Unsigned AX Attributes
During the OpenID authentication process, an OpenID consumer, like iDoneThis, can request and receive an OpenID user’s email address as part of the Attribute Exchange (AX) extension. Last year, based on research from Wang, Chen and Wang , Google and the OpenID foundation published security advisories  that pointed out that certain OpenID implementations did not check that certain information passed through AX was properly signed. The Google advisory highlights one possible exploitation of this vulnerability:
“A specific scenario identified involves a website that accepts an unsigned AX attribute for email address, and then logs the user in to a local account on that website associated with the email address. When a website asks Google’s OpenID provider (IDP) for someone’s email address, we always sign it in a way that cannot be replaced by an attacker. However, many websites do not ask for email addresses for privacy reasons among others, and so it is a perfectly legitimate response for the IDP to not include this attribute by default. An attacker could forge an OpenID request that doesn’t ask for the user’s email address, and then insert an unsigned email address into the IDPs response. If the attacker relays this response to a website that doesn’t notice that this attribute is unsigned, the website may be tricked into logging the attacker in to any local account.”
Since our implementation utilized django-social-auth’s email-based account association feature, we were potentially vulnerable to such an attack. We weren’t able to find any documentation or reports that indicated the python-openid library checked for properly signed AX attributes, so we peformed our own security audit of the code. Our audit showed that the current version of python-openid (2.2.5) does, by default, only return properly signed AX attributes. The crucial snippet of code comes from ax.py in the python-openid library:
def fromSuccessResponse(cls,success_response,signed=True): """ @param signed: Whether non-signed args should be processsed. If True (the default), only signed arguments will be processsed. @returns: A FetchResponse containing the data from the OpenID message, or None if the SuccessResponse did not contain AX extension data. """ self = cls() ax_args = success_response.extensionResponse(self.ns_uri, signed)
The django-social-auth code utilizes this default behavior of python-openid, meaning we were in the clear with regard to this attack.
Proper Usage of Signed AX Attributes
As we were researching this OpenID security issue, we found a number of people advising against the use of any AX attribute (including an email address) as a means of identification. One poster on the OpenID mailing list wrote:
“Actually, you should never use anything but the openid.claimed_id in the positive assertion to identify the user. This or openid.identity are the only values that could possibly be used to identify the user.
The chairman of the OpenID foundation himself, wrote on his blog :
“The correct behavior is to identify the user using openid.claimed_id. Other parameters MUST NOT be used to identify the user. If RP uses any other parameter to identify the user, then it is a security hole. This is the root of problem.”
Given these emphatic warnings against using an email address AX attribute for identity related purposes, we thought long and hard about the security implications of using the email address AX attribute as a means of identification for our Google Apps Marketplace and Chrome Web Store OpenID sign-in integration. The core issue is that the OpenID protocol was designed to provide identity and not trust between the OpenID provider and the consumer. An OpenID provider will always attest to a user’s unique identity (the openid.claimed_id or openid.identity attributes), but in general cannot be trusted to validate attribute information like a user’s email address. For example, the I Done This OpenID provider can properly attest my identity to be mike.idonethis.com, but could falsely advertise my email address as email@example.com, even with properly signed AX attributes. This behavior could be leveraged by an attacker to gain access to accounts owned by firstname.lastname@example.org if the consumer gives account access based on the email address provided by the untrustworthy OpenID provider.
In the specific case of Google Apps Marketplace however, the discovery URL and the resulting OpenID endpoint will always be a Google Apps OpenID server. This means that if we trust Google’s OpenID servers to only provide email addresses that are properly owned by their respective Google Apps users, we can trust the user’s ownership of these email addresses. Based on the security architecture and policies of Google Apps, the email address associated with a Google Apps account must always be owned by the Google Apps user. Non-Google Apps email addresses can also be associated with a Google Apps user, but the user must verify ownership of those additional email addresses. Because of this unique situation and context, we trust email address AX attributes provided to us by the Google Apps OpenID providers and use them for features such as associating existing I Done This users with Google Apps users. The same policy restrictions hold for Google Chrome Web Store users; the Google account OpenID provider is wholly controlled by Google and requires all associated email addresses to have their ownership verified.
Side Note: Reusable Credentials
One minor issue with email addresses as identification credentials is that they are potentially reusable. email@example.com is currently my email address, but could potentially in the future be assigned to another person. Reuse of email addresses is not an issue that we’re concerned with as it common practice across the web to assume ownership of an email address implies ownership of the identity. Just about every web service provides account recovery via email. Comments to: firstname.lastname@example.org