I have an app with free and pro versions. The pro version propose a migration assistant to import data from the free to the pro version when a user buy the pro after using the free.
I added a custom permission to protect the free version data. Both versions have the permission declared in their manifest, and only the pro version has the uses-permission.
It works well on pre-Lollipop devices, but on Lollipop, I get a INSTALL_FAILED_DUPLICATE_PERMISSION error message if I try to install the pro version when the free is installed. It works if I sign both versions with the same key (in debug for instance), but I didn't on the Play Store, and it can't be changed.
So, is there any solution, or are the permissions broken on Lollipop ??
is there any solution
In your case, you may be able to get away with Derek Fung's approach, since there is a clear installation order (few, if any, people will install the free app after installing the paid app).
Alternatively, you can skip permissions, since in this case, there are two apps that need to communicate with each other. You know what those apps are, and you know their signing keys. Perform your own validation as part of your IPC work:
Use Binder.getCallingUid() to get the UID of the calling app.
Use PackageManager and its getPackagesForUid() to find the application ID(s) associated with the UID. In your case, there should be just one, and you can confirm that the application ID is the expected value.
Use my SignatureUtils class (or just grab the code for it) to validate that the signing key of the calling application matches the expected value.
are the permissions broken on Lollipop ?
The behavior that you want — any app can define any other app's permission — is dreadful from a security standpoint.
Such "feature" would also prevent creating / using 3rd party content providers, because if your app is installed first, you need to have the permission's declaration
Custom permissions are designed for cases where there is a clear order of installation (e.g., pre-installed apps, host and plugins). Custom permissions are not well-suited for peer scenarios, where the order of installation is not pre-determined.
In some cases, this can be worked around by grafting in plugins where they might ordinarily not be needed:
App A wants to use the provider published by App B, but App A might be installed first
The author of App A creates a plugin (A') that has the <uses-permission> for App B's provider and mediates communication with App B
App A invokes something on A' when A' is installed (e.g., sends a broadcast to a specific component), so A' can validate that App A and App B were installed before A'
When the user tries to do something that involves A talking to B, if the plugin is not installed, lead the user to install the plugin
Clunky, but it should work.
It is likely that you both of your free and paid app has declared permission of the same name like below.
<permission android:name="com.example.permission" android:label="test_permission" android:protectionLevel="dangerous"></permission>
Edit:
For your case, seems you should only declare your permission on your free version. For your paid version, remove the <permission> tag and leave only the <uses-permission> tag
Related
I have gone through the available documentation and SO posts on both these topics (custom permissions and app signature), my understanding is:
Apps signed with same key can use signature-level permissions
A custom permission should only be defined in one place and the app declaring the permission needs to be installed first
A custom permission can be defined in multiple apps if the apps share same signature
Now I need to define some components in one app that I will be using in another app signed with the same key, but according to this I don't need to define a custom permission and can place a signature check
If the functionality is only available to apps signed with the same signature as the providing app, you may be able to avoid defining custom permissions by using signature checks. When one of your apps makes a request of another of your apps, the second app can verify that both apps are signed with the same certificate before complying with the request.
I don't understand what is meant by signature checks, is there a way to place a check in manifest on that component or do I have to check it programmatically? If latter, isn't it better to define a custom permission in both apps instead (to negate installation order issue)?
is there a way to place a check in manifest on that component
No, sorry.
do I have to check it programmatically?
Yes. This pair of old projects demonstrate a bound service and a client that checks the signature of the service. Those projects are covered in a chapter in a chapter of this free old book. That sample has problems in modern Android, as an app can have multiple signatures. But, the SiganturesUtil class that it relies on shows how to get signatures from PackageManager for an installed app. You can then compare them with the expected value to determine if you are indeed talking to the app that you expect.
If latter, isn't it better to define a custom permission in both apps instead (to negate installation order issue)?
Signature checks are more flexible — they are not limited to two apps being signed by the same signing key. That, plus historical issues with custom permissions, may be why Google recommends signature checks over custom permissions on that page.
For months I've been trying to publish an app with READ_CALL_LOG permission to no avail.
App is a contact management app including scheduled meetings, calendar and other events.
I only need to be able to get incoming call number, but since it's not allowed, I've implemented full InCallService that launches activity to display calling window with common answer/hang up buttons and few that redirect to our main app.
I've updated "App content" section "Sensitive app permissions" with checked "Default phone handler", provided instructions for review.
Latest version of the app is deployed in internal track. But I also have older rejected versions in beta, alpha and production tracks
App itself on first launch asks permissions to become a default Call App, otherwise won't even start.
And yet, no matter how much I try, I keep getting "App rejected" in Play store "Policy status" section. Going to see further details I get:
Issue: Violation of Permissions policy After reviewing your app, we
found that it doesn’t qualify to use the requested permissions for the
following reason(s): Requested permissions do not match core
functionality of the app You declared Default Phone handler (and any
other core functionality usage while default handler) as the core
functionality of your app. However, after review, we found that your
app does not match the declared use case(s). Learn more about
permitted uses and exceptions. Please either: • Make changes to your
app so that it meets the requirements of the declared core
functionality or, • Select a use case that matches your app’s
functionality
With "Eligibility issue" below:
Sensitive permission Your app does not qualify for use of the
requested permissions. Permission requests should make sense to users.
You may only request permissions that are necessary to implement
critical current features or services in your application. You may not
use permissions that give access to user or device data for
undisclosed, unimplemented, or disallowed features or purposes.
To my understanding if I declare the intent of using app as a default phone call handler and make that explicitly clear to the user I should be able to publish this app? Being able to detect call number is a core functionality for the app.
I've tried reaching out to support multiple times, but they just write, that they'll contact me via email to never be heard from again.
Any suggestions on what could be improved?
I have two application which are signed with different certs/keys.
I want to make authenticated call (to a service) from application A to app B (so no 3rd party can make such call).
Common solution for such things in Android is custom permissions with signature protection level. However, it won't work in my case, because two apps are signed with different certs (developed by different companies)
So, the question is. What is the best practice for this case, if I want allow only application A (or any apps developed by this company) to call/bind a service in app B?
There really isn't one, IMHO.
If the permission is not signature-based, the user can grant it to any app that asks for it, so a permission will not help you.
If you use services with the binding pattern, your Binder has getCallingUid(), which you can use to find the UID of the calling app. With some work, you can find out the package name for that UID from PackageManager. How you validate that package name is up to you (baked-in whitelist, try to make sense of the package's signature from PackageManager, whatever). That doesn't prevent somebody from messing with your APK and hacking your validation routine, though.
My application define a permission with android:protectionLevel="signature".
<permission android:name="my.app.permission.EXAMPLE" android:protectionLevel="signature" />
My intention is make application modules that can be launched only by my signed app. These application modules have android:permission in its activities.
This works fine. but...
A third-party app can use the same permission name and changed the protection level to normal, like this
<permission android:name="my.app.permission.EXAMPLE" android:protectionLevel="normal" />
If my app is installed first, i can prevent others apps to override the permission. However, if one uninstalls my app and then installs his app it redefines the permission.
Is it possible prevent other application use the same permission name, for example, giving the permission a unique id like application package?
Although the Manifest is encrypted, anyone can read the permission name in log cat when it tries to start the activity that requires this permission (An exception is thrown having the required permission name).
There's no enforcement, only convention. Like the rest of the Java world, it loosely relies on domain name registration infrastructure. The idea is that you prefix your permission name with your public Internet domain name (e. g. com.myawesomecompany.myapp.MYPERMISSION) which you own.
Uniqueness of domain names is enforced by the registrar community, naturally.
Yes, the system is open for abuse.
EDIT: if you're securing a broadcast-based channel, you can add a two-way signature check if you feel like it. Call Context.sendBroadcast() with the permission name as a second parameter.
EDIT2: I feel you're overthinking this while closing your eyes at the bigger Android app security picture. Which is not impressive. Abusing the privilege infrastructure is not how one hacks into an Android app. If I set out to intercept your intents, I won't be putting together a fake intent receiver (activity, service). Instead, I'd connect with a debugger to the genuine receiver in your app, signature and all.
With publicly available tools, it takes minutes to put togther an Eclipse project for a given APK. Load it up into Eclipse, connect to a running process, set breakpoints in relevant system APIs (Android is open source, remember), voila. With a bit of extra effort, you can get decompiled Java sources for an APK and debug in terms of YOUR methods, as opposed to system ones.
copyed from Google Andorid Doc:
Note: The system does not allow multiple packages to declare a permission with the same name, unless all the packages are signed with the same certificate. If a package declares a permission, the system does not permit the user to install other packages with the same permission name, unless those packages are signed with the same certificate as the first package. To avoid naming collisions, we recommend using reverse-domain-style naming for custom permissions, for example com.example.myapp.ENGAGE_HYPERSPACE.
https://developer.android.com/guide/topics/permissions/defining
If you want to prevent other applications from changing your permission level, you can use system predefine permissions which have level "signature". No other regular app can define permission before system.
Use system permission to protect your resource doesn't mean your app have to sign with platform key.
example:
<service
android:name="xxx.xxx.xxx.exservice"
android:permission="android.permission.BROADCAST_PACKAGE_REMOVED" >
The only issue is AppStore would show which permission you use if below code shows in app's manifest.xml
<uses-permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED" />
In this example, you can access you resource by the same sign key, but definitely you can't broadcast package remove.
What is the best way to prevent a user from downloading and installing applications which uses some specific permissions like location and sms.
Is it programatically possible to parse the manifest of an application from the market before it get installed and look for the specific permissions and alert the user?
What is the best way to prevent a user from downloading and installing applications which uses some specific permissions like location and sms.
Write your own firmware, where you replace the normal installer mechanism with one that enforces your desired criteria.
Android SDK applications cannot interfere with application installation.
Is it programatically possible to parse the manifest of an application from the market before it get installed and look for the specific permissions and alert the user?
No, sorry.
However, you can listen for ACTION_PACKAGE_ADDED and examine the newly-installed package via PackageManager, and alert the user at that point. Since nothing of the installed package can run immediately upon the install, I would think that there is a decent chance that your alert will appear before the user tries to use the newly-installed app.
In the future this would be probably something you could do trough Device Administration, but right now limiting application installation based on its requested permission is not included.
One option is this snippet that decompress the apk and extracts the AndroidManifest.xml.
By the way the aapt tool for android runs on the Android OS too. You can get this information using this port