Thứ Ba, 17 tháng 5, 2016

Improving the Security and User Experience of your Google Sign In Implementation

Posted by Isabella Chen, Software Engineer





We launched a fully revamped Sign-In API with Google Play services 8.3 providing a much more streamlined user
experience and enabling easy server authentication and authorization. We’ve heard from many developers that they’ve found these APIs simple and
less error prone to use. But when we look at applications in the Play Store, we
see many that are still using legacy Plus.API / GoogleAuthUtil.getToken and do
not follow best practices for authentication and authorization. Not following best practices can make your apps easily vulnerable to attack.


It’s also worth noting that developers who don’t want to worry about managing the security implications of different API flows or keeping up to date with the latest  APIs can use Firebase Authentication to manage the entire authentication lifecycle.




Ensuring your apps are secure




Developers should ensure that their apps are not open to the following
vulnerabilities:



  • Email or user ID substitution attack
    After signing in with Google on Android, some apps directly send email or
    user ID in plain text to their backend server as the identity credential. These
    server endpoints enable a malicious attacker to easily forge a request and gain
    access to any user’s account by guessing their email / user ID.



    Figure 1. Email / User ID Substitution Attack




    We see a number of developers implement this anti-pattern by using getAccountName or getId from the Plus.API and sending it to their backend.






    Problematic implementations, DO NOT COPY






  • Access token substitution attack
    After signing in with Google on Android, many apps send an access token
    obtained via GoogleAuthUtil.getToken to their backend server as the identity
    assertion. Access tokens are bearer tokens and backend servers cannot easily
    check if the token is issued to them. A malicious attacker can phish the user
    to sign-in on another application and use that different access token to forge
    a request to your backend.



    Figure 2. Access Token Substitution Attack




    Many developers implement this anti-pattern by using GoogleAuthUtil to retrieve
    an access token and sending it to their server to authenticate like in the
    following example:




    Problematic implementation, DO NOT COPY




Solution


  1. Many developers who have built the above anti-patterns into their apps simply
    call our tokenInfo (www.googleapis.com/oauth2/v3/tokeninfo) which is debug-only or unnecessarily call the G+ (www.googleapis.com/plus/v1/people/me) endpoint for user’s profile information. These apps should instead implement
    our recommended ID token flow explained in this blog post. Check out migration guide to move to a both secure and efficient pattern.

  2. If your server needs access to other Google services, e.g. Drive, you should
    use server auth code flow. You can also check out this blogpost. Worth mentioning, you can also get an ID token using server auth code flow,
    from which you can retrieve user id / email / name / profile url without
    additional network call. Check out the migration guide.


Improving the user experience and performance of your apps




There are still many apps using GoogleAuthUtil for server auth and their users
are losing out the improved user experience while the developers of those apps
need to maintain a significantly more complicated implementation.

Here are some of the common problems that we see:



Requesting unnecessary permissions and displaying redundant user experience




Many apps request GET_ACCOUNTS permission and draw their own customized picker
with all email addresses. After getting the email address, the app calls either
GoogleAuthUtil or Plus.API to do OAuth consent for basic sign in. For those
apps, users will see redundant user experience like:



Figure 3. GET_ACCOUNTS runtime permission and redundant user experience



The worst thing is the GET_ACCOUNTS permission. On Marshmallow and above, this
permission is displayed to the user as ‘Contacts’. Many users are unwilling to
grant access to this runtime permission.



Solution



Switch to our new Auth.GOOGLE_SIGN_IN_API for a streamlined user consent experience by providing an intuitive one-tap
interface to provide your app with the user’s name, email address and profile
picture. Your app receives an OAuth grant when the user selects an account,
making it easier to sign the user in on other devices. Learn more





Figure 4. New streamlined, one-tap sign-in experience




Getting ID Token from GoogleAuthUtil for your backend




Before we released revamped Sign-In API, GoogleAuthUtil.getToken was the previously recommended way to retrieve an ID
token via a “magic string.”




Wrong pattern, DO NOT COPY






GoogleAuthUtil.getToken needs to take an email address, which usually leads to
the undesirable user experience in Figure 3. Also, user’s profile information
like name, profile picture url is valuable information to store in your server.
The ID token obtained via Auth.GOOGLE_SIGN_IN_API will contain profile information and your server won’t need additional network
calls to retrieve them.



Solution
Switch to the ID token flow using the new Auth.GOOGLE_SIGN_IN_API and get the one-tap experience. You can also check out this blogpost and the migration guide for more details.




Getting auth code from GoogleAuthUtil for your backend




We once recommended using GoogleAuthUtil.getToken to retrieve a server auth
code via another “magic string.”




Wrong pattern, DO NOT COPY





In addition to the possible redundant user experience in Figure 3, another
problem with this implementation was that if a user had signed in to your
application in the past and then switched to a new device, they would likely
see this confusing dialog:





Figure 5. Confusing consent dialog for returned user if using
GoogleAuthUtil.getToken for auth code


Solution



To easily avoid this “Have offline access” consent dialog, you should switch to server auth code flow using the new Auth.GOOGLE_SIGN_IN_API . We will issue you an auth code silently for a previously signed-in user. You
can also check out this blogpost and migration guide for more info.




Should I ever use GoogleAuthUtil.getToken?




In general, you should NOT use GoogleAuthUtil.getToken, unless you are making
REST API call on Android client. Use Auth.GOOGLE_SIGN_IN_API instead. Whenever possible, use native Android API in Google Play services
SDK. You can check out those APIs at Google APIs for Android.

And starting from Google Play services SDK 9.0, you will need to include -auth SDK split to use GoogleAuthUtil.getToken and related classes


AccountChangeEvent/AccountChangeEventsRequest/AccountChangeEventsResponse.


dependencies {
compile 'com.google.android.gms:play-services-auth:9.0.0'
}

Không có nhận xét nào:

Đăng nhận xét