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.
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.
I want to export a ContentProvider for use by another one of MY apps. How do I prevent other apps from accessing it? If I use an android:permission attribute, can't 3rd party apps just apply that permission to their app? I really need to lock down access to my apps only.
Thanks in advance...
If I use an android:permission attribute, can't 3rd party apps just apply that permission to their app?
Well, you can use a signature-level custom permission (android:protectionLevel="signature"). Then, the app holding the permission and the app defending itself with the permission have to be signed by the same signing key.
There's a bug/limitation in Android that can allow an attacker, installed before your app, to hold this permission even though the attacker is not signed by your signing key. I go into that in more detail in this report (as it's a bit complex for an SO answer) and have a PermissionUtils class to help you detect that case.
Context:
Suppose we have two Android apps installed, A that contains a custom Authenticator code and can add new accounts to AccountManager, and B that we want to have single-touch sign in flow. You can assume the account has not yet been created in AccountManager by A.
Question:
From the perspective of B, what are the advantages of using AccountManager's addAccount method, which would require declaring android.permission.MANAGE_ACCOUNTS in the AndroidManifest of the B) over exporting the LoginActivity from the A app, and simply calling it via an intent, to create that account for B. Naturally, A already declares all required permissions. If you think the latter solution is actually better (because we don't need to declare yet another permission), I would also like to know, if you have something interesting to say to support your opinion.
You can assume I don't need to protect LoginActivity with a permission, although it is exported, because the only side effect it has is creating the account in AccountManager, which is exactly what we need.
Misc:
To give more context, if this helps answering my question:
in case A is not installed, B falls back to its own sign in form (but does not act as an authenticator and does not create an account, the retrieved OAuth token is only used by B)
B does declare INTERNET permission
both A and B are signed with the same release key
A and B do not share android:sharedUserId
On one hand it is a good idea to have an app with almost no permissions on the other hand this is some kind of cheating to use a second app for communication with the internet.
IMHO it is very important that you have a plan in case your AccountManager app gets uninstalled. In this case you have a big problem, depending on your authorisation process.
However with the PackageManager you can see if both apps are installed.
It's a good idea to make the other app optional. If both apps have at minimum the internet permission it won't make the impression of cloaking the communication. A special permission whould have the benefit that no other app can use your public API/intent. I don't know your design and if this could be a problem. However even if you use a seperat permission a malicious app could also ask for that permission.
I have a paid android application which uses the google LVL code to authenticate users.
A company would like to pay me so that their application can include a free version of my application. However, I'm not sure how to accomplish this in a way that won't result in an easily pirated version of my app. Below are some implementation options I am considering, but none of them seem like particularly good ideas. Any suggestions?
I deliver them an apk which does not use the LVL code. They could then package my apk with their app, and install it using the ACTION_VIEW intent. This seems like a bad idea because I think it wouldn't be particularly hard for some rouge user to extract my unsecured apk and distribute it.
Maybe I could build a version that checks to see if their app is installed, and if it is it queries their app for some sort of unlock code. And app will only run if this unlock code succeeds. My main concern about this is that I have no idea if "querying another app" for an unlock code is accomplishable.
This is definitely accomplishable. As already said one way to query the app is by using a content provider. If you are concerned about security you can introduce additional permission that both apps must hold to access the provider. Although since it doubtfull that both apps have the same signature it won't be as effective.
Another way would be if they had a service that you could bind to and request a code or any other authentication. In this case their service can as well validate your apps validity by querying your apps userId and checking a signature via PackageManager.
Sad news is it's alomost impossible to prevent pirating your app anyway. Even with LVL... Since all this can be decompiled and eventually broken. But at least you can make attackers life harder.
For what you are looking to do I would create a jar out of your project and mark it as a library project. That way you can give your application out to your client but they wont be able to see the actual code you have written. Using this method they will be able to call any method directly which would be easier than having to interact with an apk.
I was under the impressions that two apps were sandboxed and unable to call each other (by intents or contentresolver etc) unless the callee declared and enforced specific permissions and the caller used appropriate uses-permission elements? However, I have developed two apps, one containing a content provider, and another with activities that use the content provider. Neither have permissions declared enforced or used. I deploy them directly from Eclipse to my phone and they are able to use each other.
I have checked that they really are running as separate processes and user ids, and they are. Why am I not seeing security exceptions? Should Linux underneath, by default, stop this communication? They will be signed by the default DEBUG certificate. Does this give them more rights to "talk" to each other, i.e. if I signed with an explicit certificate would the sandboxing kick in?
As soon as I declare and enforce a permission in the content provider app the other app does need the uses-permission to allow communication.
Cheers
Yes, if your apps have the same signature, then they have access to each other. It's similar to package level permissions in java.
http://developer.android.com/guide/topics/security/security.html