Posted on by Vulnerability Mitigationin
The Google Identity Platform is a system that allows you to sign in to applications and other services by using your Google account. Google Sign-In is one such method for providing your identity to the Google Identity Platform. Google Sign-In is available for Android applications and iOS applications, as well as for websites and other devices.
Users of Google Sign-In find that it integrates well with the Android platform, but iOS users (iPhone, iPad, etc.) do not have the same experience. The user experience when logging in to a Google account on an iOS application is not only more tedious than the Android experience, but it also conditions users to engage in behaviors that put their Google accounts at risk!
Before getting into the details of Google Sign-In on iOS, it is worth it to take a brief detour to discuss when it is appropriate to provide your account credentials in general. Whether you are dealing with a web page, a desktop application, a mobile application, or anything else, there are certain questions that you should answer before you can safely provide authentication information:
You can't always answer all of these questions. Keep in mind, however, that any time you can't answer a question, you are placed in a situation where an attacker may be able to obtain unexpected access to your account.
What happens if you can't answer the question, "What application am I interacting with?" If you don't know what application is providing the dialog you're working with, then you can't begin to guess what will happen with the information that you provide. For example, see CERT Vulnerability Note VU#490708 - Microsoft Internet Explorer window.createPopup() method creates chromeless windows.
Also, what happens if you can't answer the question "Where does this information go when it's submitted?" This is a difficult question to answer. When dealing with web pages, the easiest starting point is to know what website you are currently viewing. If you're viewing look-alike content on a domain that is other than what you expect it to be, then it's possible that you may end up providing credentials to an attacker. Most phishing attacks use this technique. To complicate the matter further, a website that is vulnerable to cross-site scripting (XSS) may allow an attacker to obtain your credentials, even if you are currently viewing the legitimate website in question. For example, see CERT Vulnerability Note VU#808921 - eBay contains a cross-site scripting vulnerability.
Finally, what happens if you can't answer the question, "Is the information protected in transit?" Especially on mobile platforms, this question can also be difficult to answer. If an application chooses to not use encryption, or if it improperly implements encryption, this situation can allow an attacker to observe sensitive data in transit. In a case where you are providing credentials to an account, an attacker may be able to compromise the account. For example, see CERT Vulnerability Note VU#432608 - IBM Notes Traveler for Android transmits user credentials over HTTP.
Especially when you can't answer one or more of the above questions, it's important to consider the risks that may be involved with providing your account credentials. In this blog post I explain why the Google Sign-In experience on the iOS platform forces you to take unnecessary risks.
Google APIs use the OAuth 2.0 protocol for authentication and authorization. Without getting into the nitty gritty details, OAuth allows you to authenticate with a system without needing to divulge your credentials to a third party. For example, if you want to authenticate yourself with the Pokémon Go application by using your Google account, OAuth should allow you to do it without ever telling Niantic your Google credentials.
At least, that's the way it works with the Android version of the game. Why is iOS different? To understand the differences, let's look at the sign-in process for each.
With most Android devices, the OS itself is associated with a Google account. When you turn on your new Android phone, one of the first steps is a prompt to log in with your Google account credentials. This account is tied so closely with the OS that many Android phones force a factory reset if the Google account is removed from the phone.
Google Sign-In on an Android device leverages the Google account that is associated with the device. When the getSignInIntent is invoked, the authentication process is handed off to the Android OS itself. Here you can select which Google account to use. No password is required. If the application needs permissions beyond profile, email, or openid, then you are prompted to grant access to the additional resources.
Because you are not prompted for any credentials, the three questions outlined above are not terribly important:
The reason that these questions are not important is because you are not directly providing sensitive information. You are simply choosing whether or not to grant access to the account access levels that are requested.
With iOS devices, there is no OS-level association with a Google account. Therefore, there is no already-authenticated component that Google Sign-In can leverage to achieve its goal. As a result, you must enter your Google username and password directly into a screen that is presented by the application.
Let me be clear about what happens during the sign-in process:
Doesn't this sign-in process violate one of the main aspects of OAuth? That is, you shouldn't have to enter your credentials to a third-party application or site with OAuth. As it turns out, when Google Sign-In is used on iOS, the dialog is indeed on the Google website. So the third-party application is not receiving your credentials. But how do you know this for sure? To find out, I launch an application, and click a button that looks like this:
As a result, I'm presented with a screen that looks like this:
Update (August 10, 2016): The above screenshot is from an iOS 8.x device.
At this point, I think that the dialog is presenting content from accounts.google.com. But I have no way of verifying it. Even if clicking the "accounts.google.com" text did something, how do I know that the whole screen isn't being faked?
As a user, I have no idea what is providing the screen that I'm seeing. All I know is that I launched an application that I may or may not trust, and it's now prompting me for the credentials to my Google account. This situation is much like website spoofing on PCs, but it's even worse on mobile devices due to the limited screen real estate and limited information presented to the user.
I can't answer the three questions outlined above easily.
By looking at the Google Sign-In for iOS code, it appears that the sign-in dialog is created using a UIWebView object. This object doesn't share cookies with Safari, though. This means that even if Safari is logged into Google on my iOS device, the Google Sign-In code will not know it.
Update (August 10, 2016): The UIWebView object is only used on iOS versions earlier than 8.x. On iOS 9.x devices, Google Sign-In library version 2.3 (Released Sept. 29, 2015) and newer will use the SFSafariViewController object, which will leverage Safari cookies. This means that if the user is already logged in with Safari, the application that uses the Google Sign-In library will not prompt the user for credentials. Version 2.0 through 2.2 of the Google Sign-In library used a UIWebView object to avoid the limitations introduced in iOS 9.0, where applications were not allowed to launch Safari for the purpose of logging in.
If an app author chooses to use something like the SFSafariViewController, or uses Google Sign-In version 2.3 or newer, then the Google authentication process can leverage an already-authenticated Safari browser. For example, here is a screenshot of an application that appears to use this technique:
Here I can see that the authentication process knows who I am already, and I simply have to choose "Allow" or "Deny." I don't have to enter my password, which, as it turns out, is a good thing, as Safari and its associated components appear to expose no way of viewing an SSL certificate. Even if I click the Safari icon in the bottom-right corner, which opens the same page in the full-blown Safari browser, the padlock does nothing when I touch it.
Even though I can't view the site certificate, I'm comfortable with clicking either "Allow" or "Deny" here. Even if the application is malicious, all it can do is view my email address and my basic profile information. The important part to realize is that I did not enter my credentials anywhere. Had I entered my Google credentials into the application, it could possibly have done anything that it wanted with my account.
This is exactly what happened with the Pokémon Go application when it was first released. When a user launched the application and clicked the "Sign up with Google" button, the user was presented with a screen where the username and password must be entered. After this action was taken, Adam Reeve noticed that the application had full access to his Google account.
This incident made me wonder how the application was able to gain full access without explicitly asking for it. The answer is perhaps obvious--the user entered Google credentials into a screen presented by the application. It doesn't matter if the recommended Google authentication technique is used or not. The user gave Google credentials to the application.
Niantic has since published a statement about how the application erroneously requested full-access permission to the Google account, and that it accessed only the user ID and email address. I didn't reverse engineer the original version of the application, so I guess I'll just have to take their word for it.
Google isn't the only organization that provides an authentication API for third-party developers. Facebook Login can provide similar capabilities on Android, iOS, websites, and other platforms. There's an important difference between the Google Sign-In and Facebook Login tools though: Facebook Login works on iOS devices in the same way that it does on Android devices. That is, when an application uses the Facebook Login API, it launches the Facebook application (if installed) on the phone, and within that application I can see what is going on:
Let's go back to our three questions:
In the case of using a Facebook Login, it's pretty clear that I'm dealing with the Facebook application, as I am already logged in. I can verify this by double-tapping the home button if I like. The second two questions are more difficult to answer, but if I trust the Facebook application, I'm likely to believe that it is doing the right thing.
Being the security-conscious person that I am, I consider the risk of providing my credentials because I can't answer all of the above questions. And because I'm not providing my Facebook credentials at all here, I simply review the account access I would be providing to the app and choose to proceed or cancel based on the level of access I'm comfortable with providing.
Why is Facebook able to handle authentication properly on iOS, but Google is not? The Facebook application has registered itself as a handler for Facebook Login requests. Any third-party application that attempts to use Facebook Login causes the Facebook application to launch and handle the request. As the Facebook application itself is already authenticated with the Facebook servers, it can delegate privileges to third-party applications without the need to share credentials, just like OAuth is supposed to work.
If a user doesn't have the Facebook application installed, then Facebook Login will fall back to using Safari. In this case, if I've already used Safari to log in to Facebook, I still won't be prompted for my Facebook credentials. I simply see a web browser page similar to the Facebook application screen above. I'm only prompted for Facebook credentials if I never logged in to Facebook using Safari and I don't have the Facebook application on my iOS phone.
When implemented properly, OAuth can help protect account credentials. Google Sign-In on iOS does not achieve this goal, however. By conditioning users to enter Google account credentials on a whim, Google has created an environment where users are more likely to have their accounts compromised.