Is it possible to add a filter to a content provider to make it accept only requests coming from a set of known application IDs?
For example, if com.domain1.app1 and com.domain2.app2 are two app that I trust I'd like to make them read my data. Any other application should be kept outside.
Something like intent filter but related to incoming request from other applications.
I know about the same signing key but it's not what I need.
If a provider's application doesn't specify any permissions, then other applications have no access to the provider's data. However, components in the provider's application always have full read and write access, regardless of the specified permissions.
As seen here.
Related
I am trying to determine how to access a ContentProvider which exists in another profile.
I have an app/service in the managed profile which implements a content provider.
I have a 2nd app/service in the primary profile and I want it to be able to access the managed app's content provider. i.e. cross-profile
Right now I am prototyping the implementation using a modified version of android-testdpc. I have added a ContentProvider to the testdpc source. I want to be able to access this ContentProvider, which is in the managed profile, from another app that is running in the primary profile.
I know that using DevicePolicyManager.AddCrossProfileIntentFilter() I can allow intents sent in the managed profile to also be resolved in the parent, or vice versa. The documentation states that only activity intents are supported. Using AddCrossProfileIntentFilter() I have successfully been able to pass data between the two apps by using intents and startActivity().
However, using activities is not what I want to do since in Q and later I cannot start an activity from a background app/service.
I have no problem accessing the ContentProvider if the two apps exists in the same profile but I have been unable to determine how to make this work cross-profile.
I finally got this working.
To do so I needed to use an activity in the content provider to give permission to the other app. The non-content provider app must send an intent to an activity in the content provider app, requesting permission to access the content provider, using startActivityForResult().
This activity returns an intent, setting the content provider URI with Intent.setData() and permissions with Intent.setFlags(). In my case I included Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION to make the permission persistent.
The non-content provider app gets the result intent in onActivityResult(), gets the URI from the result then calls ContentResolver.takePersistableUriPermission().
To make this work cross-profile I used DevicePolicyManager.addCrossProfileIntentFilter() to allow the permission request intent to cross profiles. When crossing profiles I noticed that the content provider URI returned in the result intent include the user id. i.e. “content://10#com.example.myprovider/test". Making a query using this URI will cross profiles.
This helped https://www.futurelearn.com/courses/secure-android-app-development/0/steps/21592
How can we ensure that certain applications are not able to access my data stored in content provider where in certain other applications can access that? Basically I need to allow some application of my interest to access my data stored in Content Provider but I do not want all the applications to be able to access that data. How can I achieve this?
Thanks.
The easiest way is to protect the content provider with a permission you define. Make it a signature a permission so only apps signed with your certificate are allowed to get it.
See:
http://developer.android.com/guide/topics/security/security.html
http://developer.android.com/reference/android/R.styleable.html#AndroidManifestProvider
http://developer.android.com/guide/topics/manifest/provider-element.html
If doing this based on certificates is not sufficient, you will need to write the permission checks yourself. This is done by calling Binder.getCallingUid() for incoming calls to your applications, and deciding whether the given uid has permission to access your provider. Actually implementing a different policy that is actually secure requires a lot of careful thought and design, though.
In the AndroidManifest.xml, at the screen with the properties of your ContentProvider, you have two fields:
Read Permission
WritePermission
So, you can define secure strings (also it may be path to some file) that are permissions for acces to your ContentProvider.
Applications that want to access your content provider must have that ones added in their UsesPermission elements.
I have an application, say ApplicationProvider, which holds a provider and a receiver.
Another application, say ApplicationCreator, creates an element on the provider through an intent. The ApplicationProvider get the intent and creates the element accordingly.
Now I would like ApplicationCreator to be the only one to hold the rights to access that element. So if another application tries to access that element, this generates some kind of error.
What is the best way to do so? I came up with two possible solutions, but I don't like any of them.
1) ApplicationProvider denies any direct access to the provider, instead uses the receiver to get the intents which are sent through intentForResult, so the receiver can check the caller, verify that is the original caller who created the element and grant access. Other applications would get denied because they hold a different uid. Since there is no easy way to forge the uid, this system works.
2) Any application can send intents to the provider but in the manifest i specify all the path-level permission to the single uris that are created. I manually issue an update to the application every time someone wants so create a new element.
=========================================
Additional information:
It would be ideal if different applications could put different elements and be able to retain the rights to modify those elements they created and also grant permission on those elements to whom requested said permission.
A---> +--------+ A creates content
| pro | <---B B asks permission
A<----| vid | the provider forward permission
A---->| er | A grant permission
| | --->B B is given permission and can access A's stuff
+--------+
Here are my thoughts on this topic. No code is provided, since I did not implement anything. Also, I'm not entirely sure that this solution is entirely secure.
First, authentication.
Every client who wants to use your content provider needs a key. Each client fetches one key from your application (maybe implement a content provider for that). A random sequence of letters / numbers should be fine. This key is stored within your application and the clients application, somewhere where noone else has access, i.e. a private database / preference property.
This key is used to authenticate a client application with your content provider. On each request, this key (maybe a hash of the key) is included within the request uri (much like API keys when using REST web services). Your application checks whether the provided key was previously generated. If that is the case, authentication is successful.
Next, authorization.
Each element in your database has a field ownerKey. When creating new elements, this field is filled with the key provided with the request. When accessing / modifying / deleting elements, your content provider should check whether the stored key matches the submitted key. Only perform the operation if the keys match.
Additional thoughts.
The whole point is that the random keys generated by your application stay private. I'm not sure whether it is possible for a third party to intercept interaction between a client application and a content provider. You might want to investigate this before writing any code.
Specifying a key on each request could be optional. When omitting a key during element creation, those elements do not have an ownerKey and thus are allowed to be accessed and modified by anyone without authentication/authorization.
I hope this helps somewhat.
I would suggest the uid approach, but there is no reason for this to go indirectly through a receiver. Just store the owning uid for each row in your database, and on incoming calls to the content provider use Binder.getCallingUid() to retrieve the uid of the current caller which you can validate against the row they are operating on.
What would be the best strategy to define custom (application specific) permissions in Android?
I have an application of which part of it is accessible without requiring a login. But part of the application functionality is to be restricted to users who actually have logged in. I was trying to think of the best way to do this on Android and was thinking on the lines of defining a permission in the android manifest. But is this is the right tool for the job?
I come from a world where user permission are as easy as putting annotations on the class #admin, #manager. Nothing of that I suppose in the Android world.
Also my concern is I do not want the user to see my custom permissions while installing the app since it might just confuse/scare him for no reason.
Wanted to ask how people approach this issue? Do they just hardcode a utility method isLoggedIn() and call it before executing anything that requires permission?
I maintain a cookie when a user logs in. If that cookie is not set, I give them the un-authenticated experience. If the cookie is set, I use it to make service calls.
When querying a ContentProvider on Android, one specifies the ContentProvider of interest by providing the "content URI" for that ContentProvider. What happens when multiple ContentProvider's serve that same URI, either intentionally? or maliciously?
When trying to open a pic on my phone, I've seen it prompt with apps that can "handle" the image. Will the same kind of thing happen here?
Multiple ContentProviders can't do this. The first application that registers a content provider using the element in its manifest has control over the URI pattern. I'm pretty sure that you'll get an installation error if you try to add another provider that uses the same URI pattern. Android keeps track of providers and URIs.
When you see a prompt with multiple apps for handling a file or situation, that's because the apps have specified an with a child that includes
android.intent.category.CATEGORY_ALTERNATIVE or android.intent-category.CATEGORY_SELECTED_ALTERNATVE. In essence, the app or apps are declaring themselves to be alternatives to the action specified in the child. This allows the user to have multiple choices for handling a type of data.
It makes sense to provide alternatives: a user might want to edit a picture, share it via Twitter, or e-mail it.
Note that two content providers can do the same thing, but they can't use the same URI. An app has to make a conscious choice of which one to use, or provide some mechanism of choosing between the two.