Search code examples
androidandroid-security

Intent Redirection Policy Violation - Rejected after Fixing by Following Provided Documentation


We have received the following policy violation after implementing the Google Play SMS retriever for two-factor authentication. After fixing it by following the documentation and resubmitting, it was rejected again.

Step 1: Fix the policy violation with your app

During review, we found that your app...APK Versions..., violates the Device and Network Abuse policy:

We don’t allow code that introduces or exploits security vulnerabilities. Check out the App Security Improvement Program to find out about the most recent security issues flagged to developers. You can read through the Device and Network Abuse policy page for more details and examples of common violations.

For example, your app contains an Intent Redirection issue which can allow malicious apps to access private app components or files.

{package name}.modules.smsuserconsent.c.onReceive


Following the documentation (https://support.google.com/faqs/answer/9267555) we have decided to fix it by using: Option 2:

Option 2: Ensure that the extracted Intent is from a trustworthy source.
You can verify that the originating Activity can be trusted using methods like getCallingActivity. For example:

 if (getCallingActivity().getPackageName().equals(“known”)) {
   Intent intent = getIntent();
   // extract the nested Intent
   Intent forward = (Intent) intent.getParcelableExtra(“key”);
   // redirect the nested Intent
   startActivity(forward);
 }

Note:

  • Checking if getCallingActivity() returns a non-null value is insufficient to prevent the vulnerability. Malicious apps can supply a null value for this function.
  • In the case of Google Play Services SMS Retriever Auth, protecting a broadcast receiver with the SEND_PERMISSION will ensure that an Intent comes from Play Services.

It specifically calls out our use case and that by passing SEND_PERMISSION, it should be enough to address the policy violation.


This was our old code:

SmsRetriever.getClient(getCurrentActivity()).startSmsUserConsent(null);

broadcastReceiver = new SmsBroadcastReceiver(getCurrentActivity(), this);
getCurrentActivity().registerReceiver(
  broadcastReceiver,
  new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
);

This is our new code:

SmsRetriever.getClient(getCurrentActivity()).startSmsUserConsent(null);

broadcastReceiver = new SmsBroadcastReceiver(getCurrentActivity(), this);
getCurrentActivity().registerReceiver(
  broadcastReceiver,
  new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION),
  SmsRetriever.SEND_PERMISSION,
  null,
  0
);

Do we still need to implement checking the calling activity in the onReceive for this or did we not implement the SEND_PERMISSION correctly?


Solution

  • We went through multiple iterations of failed reviews. We finally passed review after fully implementing option 2 and 3:

    Intent consentIntent = extras.getParcelable(SmsRetriever.EXTRA_CONSENT_INTENT);
    if (consentIntent == null) {
      //handle error
      return;
    }
    
    ComponentName name = this.activity.getCallingActivity();
    int flags = consentIntent.getFlags();
    
    if (name != null && 
      name.getPackageName().equals("com.google.android.gms") &&
      name.getClassName().equals("com.google.android.gms.auth.api.phone.ui.UserConsentPromptActivity") &&
      flags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) &&
      flags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0)) {
        activity.startActivityForResult(consentIntent, SMS_CONSENT_REQUEST);
    }