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.
Related
This is a very short answer, which I couldn't find an answer to, not in in the docs and not anywhere over the Internet:
On Android, apps can offer the user to choose files from them, to be chosen from other apps. For example, the Google Photos app allows to choose photos files from it. This is done by implementing DocumentProvider .
I'd like to ask if it's possible to offer my app's content, only to my app itself.
This can help in the case of providing photos selection, for example, that is relevant only for the app itself.
From this docs link:
Create a custom document provider
"The attribute android:exported set to "true". You must export your provider so that other apps can see it."
Set android:exported to false inside your manifest.
The DocumentProvider is a ContentProvider so looking at the documentation for ContentProvider will supply a lot more info:
ContentProvider
"false: The provider is not available to other applications. Set android:exported="false" to limit access to the provider to your applications. Only applications that have the same user ID (UID) as the provider will have access to it."
In my app, I'd like to store a persistent read permission to content provided by Dropbox (among other content providers). The Android Dropbox app doesn't support the Storage Access Framework, so to be able to select content I can't use ACTION_OPEN_DOCUMENT -- instead I need to use ACTION_GET_CONTENT.
However, it seems that some content providers, such as Drive, don't return persistable permissions for URIs returned via ACTION_GET_CONTENT. I believe this is as expected, because GET_CONTENT URIs are not supposed to be persistable. Unfortunately I do need to persist the reference across restarts.
It seems that there is no way to get persistent permissions to a URI in recent API versions if the content provider doesn't support SAF. Is that true? What is a good workaround?
Bad (for my use case) workarounds would be: copying the content and storing it locally, relying on implementation details which are not in spec (e.g. it seems that Dropbox URIs returned by GET_CONTENT are in fact persistable), or not persisting the permission.
It seems that there is no way to get persistent permissions to a URI in recent API versions if the content provider doesn't support SAF. Is that true?
Based on my experiments, yes. More accurately, AFAICT, only Uri values obtained from a DocumentsProvider have a shot at having persistable permissions, in terms of what the framework offers. I do not see how an ordinary ContentProvider can offer this.
What is a good workaround?
Given your list of "bad" workarounds, your best workaround is to use some Dropbox-specific API to allow the user to choose the content and for you to access it over time, if Dropbox offers one.
Of the "bad" workarounds, copying the content is a likely choice — adjust your UI to tell the user that you are "importing" the content, for example, to help indicate that it is indeed a copy.
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.
I am going through the documentation for the contentprovider "exported" attribute here
Can someone pleas explain what does this statement mean :
You can set android:exported="false" and still limit access to your provider by setting permissions with the permission attribute
I always thought with exported=false, none of the external apps can access the provider. But the above statement seems contradictory.
Thanks,
Your understanding of exported = false is right. It will block access to the contentProvider to everyone.
However, with right permissions (read/write) you can create 'exceptions' so that only apps with permissions will be able to access the content Provider even if it is blocked for every other app.
also, read this question
I think that is just a typo. And what it means is that you can 'allow access' by setting it to true and that you can use permissions to limit what applications can access the content provider.
I'll look into this, since I help teach this material... (will update)
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.