13

Having issues with my apps on Google Play. I have a free app which utilizes a custom permission. This permission allows access to paid apps. These paid apps act as "keys" and unlock features in the free app. Basically the free app will attempt to start the intent of one of the paid apps. The paid app will do some stuff and return saying whether the free app should unlock features or not.

Problem arises based on the order of app installation. If the free app is installed first then a paid app, the free app can't start the intent. Returns permission denial. If the paid app is installed first then the free app, the free app can start the intent no problem. Rebooting the device and/or force stopping the apps doesn't resolve the issue. I'm attaching the relavent code. Something tells me I'm doing something incorrectly.

  • Free App Manifest (relevant code):

    ...
    <uses-permission android:name="com.company.license.PERMISSION" />
    ...
    
  • Free App Code to check intent (relevant code):

    Intent KeyApp = new Intent("com.company.license.action.AUTH_1");
    KeyApp.putExtra("com.company.license.challenge", 1);
    
    //If free app is installed first, an exception is thrown for not having the proper permission. If paid app is installed first, no exception is thrown
    try {
        startActivityForResult(KeyApp, COMMING_FROM_KEYAPP);
    } catch (Exception e) {
        cancelStartUp();
    }
    
  • Paid App Manifest (relevant code):

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.company.installer.1"
    ...
    <permission
        android:name="com.company.license.PERMISSION"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:protectionLevel="normal" >
    </permission>
    
    <application
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.NoDisplay" >
    
        <activity
            android:name="com.company.license.auth"
            android:configChanges="keyboardHidden|orientation"
            android:exported="true"
            android:permission="com.company.license.PERMISSION"
            android:theme="@style/Theme.Transparent" >
            <intent-filter>
                <action android:name="com.company.license.action.AUTH_1" />
    
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    
        <activity
            android:name="com.company.installer.redirect"
            android:configChanges="keyboardHidden|orientation"
            android:exported="true"
            android:theme="@style/Theme.Transparent" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    
    </manifest>
    
Ifrit
  • 6,791
  • 8
  • 50
  • 79

2 Answers2

13

Put the same <permission> element in both apps. Also, since this is specific to your two apps, I would use android:protectionLevel="signature" instead of normal -- this means the user will never need to approve the permission and nobody else will be able to request the permission. And, this recipe will allow installation in either order.

UPDATE: Note, however, that the use of custom permissions opens up potential vulnerabilities, due to Android's "first one in wins" approach.

UPDATE #2: And this is now no longer supported as of Android 5.0, as two apps cannot both have the same <permission> element unless they are signed by the same signing key.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 7
    Problem: if first installed app specifies and for same permission, user is not informed of permission request at install time. After second app is installed, first app can access second app's components requiring that permission. Major security problem? – Mark Jan 30 '14 at 18:04
  • @MarkCarter: The user definitely will not be prompted for `signature`-level permissions. However, that does not really depend upon installation order; `signature`-level permissions never appear. Since `signature`-level permissions are for code written by one developer (or team), the assumption is that these permissions are controlling what amounts to aggregate internal communications, and the user does not need to be bothered. If, however, you are seeing your described behavior with custom `normal` or `dangerous` permissions, that would surprise me, and I would need to do more research. – CommonsWare Jan 30 '14 at 18:09
  • Yes, I'm seeing it with "normal" (in the permission-only app). Also, since the uses-permission app can specify its own level (in permission tag), one would need only test for the different levels in the permission-only app. Having said that, I've only tested with two apps with the same signature so that could be it. – Mark Jan 30 '14 at 18:15
  • @MarkCarter: If you can post a reproducible sample project (or, in this case, pair of projects), I can take a look a them. I am having difficulty parsing the second sentence of your preceding comment, though. That may be just due to lack of sleep. – CommonsWare Jan 30 '14 at 18:18
  • I've just checked and the same problem exists with two apps with different signatures. Install App1 which has (user sees nothing in UI for that permission but log says AppSecurityPermissions: Ignoring unknown permission:com.mypermission). Install App2 which has and observe that App1 can use App2's components protected by permission. Note - if you take out then (as you would expect) the permission is never granted. I've just sent you the sample projects. – Mark Jan 30 '14 at 19:05
  • Thx for the blog post about this, please edit the answer to reflect some aspect of Marc Carter's findings. – Richard Le Mesurier Feb 14 '14 at 09:12
  • It seems Android L fixed something in this regards which now breaks apps using these techniques: https://plus.google.com/u/0/103523077374026034542/posts/CR7huubtmu4?cfem=1 – plaisthos Jul 08 '14 at 10:56
  • 2
    @plaisthos: Interesting! I will run some tests this weekend. Thanks! – CommonsWare Jul 08 '14 at 10:57
  • I read the article of @CommonsWare which was great, but it leads (especially the last part about Android L changes), to a bigger issue regarding peer apps, which is: Facebook and Twitter are definitely not signed by the same certificate. **How can one another use permissions of the other, regardless of the install order?** – David Ferrand Aug 07 '14 at 14:24
  • @plaisthos: Yes, apps can't redefine a permission already defined by another app, unless those apps are signed by the same signing key. I [wrote up my test results](http://commonsware.com/blog/2014/08/04/custom-permission-vulnerability-l-developer-preview.html). I apologize for not crediting you with this, as I made a note of the G+ post but not where I got it from. – CommonsWare Aug 07 '14 at 14:58
  • @Dadou: You are going to need to ask a separate Stack Overflow question for that, though I suspect that the answer is "it is no longer supported". – CommonsWare Aug 07 '14 at 14:59
  • I am creating an SDK that interacts with another App. It does a lot of IPC. Obviously, I can't have developers sign their apps with the same key as the App... Should I just abandon permissions use explicit intents? I am only worried about not having permissions on my Providers... – jophde Dec 08 '14 at 22:30
  • @jophde: "Should I just abandon permissions use explicit intents?" -- probably not, because an explicit `Intent` offers no security. Your app just needs to be installed first, or you need to use built-in permissions (instead of custom ones) if they would be meaningful to the user. – CommonsWare Dec 08 '14 at 22:37
  • Wouldn't explicit intents be the same amount of Security since I am the only one that knows the component names and packages just like I am the only one who knows the permission string? – jophde Dec 08 '14 at 23:16
  • I am going to go with com.android.permission.USE_CREDENTIALS now since I am basically sending an auth token over IPC from App to Client app. – jophde Dec 08 '14 at 23:39
  • @jophde: "Wouldn't explicit intents be the same amount of Security since I am the only one that knows the component names and packages just like I am the only one who knows the permission string?" -- anyone can figure those out and invoke your component, so that's not much in the way of security. However, the user is involved in the permission (other than the problem mentioned in the answer). – CommonsWare Dec 09 '14 at 00:00
  • Couldn't they just decompile the app and look at the permission string I am using in the manifest and specify that their app uses the same permission? – jophde Dec 09 '14 at 01:01
  • @jophde: Yes, but the user has to agree to the permission. The objective of permissions is to limit communications to what the *user* agrees to (`normal` or `dangerous`) or to limit communications to apps in a suite from a single developer (`signature`). – CommonsWare Dec 09 '14 at 01:04
  • Answer appears to be outdated. Any solutions for Android O or P? – denver Jun 26 '19 at 14:42
  • @denver: I do not recommend custom permissions outside of very narrow use cases (e.g., apps in a suite, all signed by the same signing key). – CommonsWare Jun 26 '19 at 14:47
  • What do you recommend when the app serves as a data provider for third party apps? – denver Jun 26 '19 at 15:05
  • @denver: If an existing system permission seems apropros (e.g., `READ_CONTACTS` for contact-style data), use it. Otherwise, I don't have a good solution for you. You're welcome to proceed as in [the other answer](https://stackoverflow.com/a/36604160/115145), defining the permission in your app and hoping for the best. Just bear in mind that if the other apps needing the permission are installed first, you're screwed, and if other apps define that permission themselves, you're screwed. – CommonsWare Jun 26 '19 at 15:11
  • @denver I found a solution for your question, but you need to be able to change (or request to change) the third party's app permission to `dangerous`. This means that you will need to show to the user the system's dialog for requesting the app permission, but since it's requested at runtime it does not matter which app order do you follow. – NeoKree Apr 12 '21 at 09:48
  • @NeoKree Interesting. Thanks. – denver Apr 13 '21 at 03:28
2

I was able to work around the issue @CommonsWare mentioned in his Update #2. Simply by only declaring the permission in the app which will be installed first.

Explanation: I have app A and app B, signed with different signatures. App A needs to use app B to login, but app A gets installed first and makes sure the user installs app B.

Because app B seems to be the (login)service I declared the custom permission in app B. App B has a (intent)service which other apps may use, as long as they use the permission and are in our whitelist. So app B had the service and permission declared.

But because app A is installed before app B I discovery I needed to add the permission as well to app A. Otherwise app A didn't seem to have the permission after installing app B. My best guess is that this is because the permission stuff is done at installation. And since app A didn't declare the permission, at install nothing happened. But then app B is installed which has the permission but app A still doesn't receive this permission.

But then I tested on Android 5 and ran into their unique permission changes. So I tested some flows and permission declarations and came up with a working solution: Declare the custom permission in the app that gets installed first! Of course this only work when you know which app is going to be installed first. But in my case, where app A is dependant on app B ánd app A installs app B, this was the solution :)

PieterAelse
  • 3,578
  • 2
  • 23
  • 33