How to securely verify a user's subscription to an Android app? - android

I know very little about security or servers, but am making an Android app that allows users to purchase an in-app subscription. As recommended, I want to use the Google Play Developer API and store the necessary data on my own server. However, I can't think of a way to do this without having a line in my code like
if(userIsSubscribed){
//give access to purchased data
}
A hacker could obviously go in and just flip that to if(true). What should I do instead?

Obfuscate your app code as a minimum. Also do the subscription check on the server, before you send the content. That is one of the reasons they have an Web API.
Basically, anything the user (and potential cracker) has access to (i.e., your app) cannot be trusted. Things they don't have direct access to (i.e., your content server) can be trusted a bit more and it is a good idea to move all sensitive operations and/or data there, where possible.

Related

Least invasive way to uniquely identify Android user

How can you uniquely identify a user who has installed your app so that:
You will know it is them if they delete and reinstall your app;
You will know it is them if they install your app on a second device they intend to use simultaneously?
Just as an example, I see that the Netflix app will automatically link to your desktop account without any user interaction. I'm guessing that they use accountManager.getAccounts() or similar method, because they also require the GET_ACCOUNTS permission. But of course that permission is marked as Protection level: dangerous. Is there any technique to do this that is less invasive or potentially alarming?
The key to answering this is to be both simple (for the user) and minimally invasive. Android provides heaps of ways to identify users and many of those ways involve piercing a user's privacy, and if that is the only way, I will do what I do now (optional email registration). I just want a way for my app to know if a user already is registered in my system across installs without having to interview the user (username/password, email address, third-party OAuth, etc).
My main reasons are:
I don't want support requests from users who orphaned their content after a reinstall; and
I don't want to host lots of orphaned content.
Have a look at Firebase Authentication. It's quite seamless and does not require much effort to incorporate. Also it does not feel intrusive or cumbersome to the end user.
Here is a video tutorial by Google.
EDIT:
In case your users are sure to have a cellular device with a phone number, you can use AccountKit. It is also what they call OTA (One Time Authentication). AccountKit uses just the users phone number to verify and validate users.
EDIT:
Firebase Authentication now features 'Phone Verification' which is similar to AccountKit mentioned above. Both are good services. However, Firebase phone verification lets you make your own UI from scratch (which means a lot better control than AccountKit). Also, if you don't want to make your UI, you can always use FirebaseUI
i have implemented something that seems little similar to your thing by push notification , i can get error if user uninstalled my app(and from the registration id i get the user) , and if he re installed he obtain a new registration id , and try to get the user UUID for different devices
I think the simplest way would be using UUID and storing the hash on sharedPreferences. You should generate the UUID as earlier as possible in your app.
sharedPrefs = context.getSharedPreferences(APP_SHARED_PREFS,Activity.MODE_PRIVATE);
if (sharedPrefs.getString("YOUR-KEY-TO-THE-UUID") == null || "".equals(sharedPrefs.getString("YOUR-KEY-TO-THE-UUID"))){
prefsEditor = sharedPrefs.edit();
prefsEditor.putString("YOUR-KEY-TO-THE-UUID", UUID.randomUUID().toString());
prefsEditor.commit();
}
I think that the best way would be implementing login with Google or Facebook. This is quite seamless for users, safe enough (as Google and Facebook considered trusted), you do not need to implement your email registration and you will have identity across devices.
If your app is Android only and you'd like to provide identity without any account creation for the user, I believe using Google Account name/id is the best choice (Accessing Google Account Id /username via Android) since you have to use Google Account on Android phone (unless you root it, delete Google Play Services etc).
If you'd like to only address the first point of your question (identify after reinstall) there's a Device Id -Secure.getString(getContext().getContentResolver(), Secure.ANDROID_ID);
though it's not 100% reliable (f.e Factory Reset resets this value)
The standard for achieving this sort of functionality is through the use of JSON web tokens (JWT) in conjunction with standard restful api traffic.
Assuming your android application interacts with a RESTful api for all crudlike operations and business logic, then using a JWT as an authentication identifier to your api can work quite well. You can embed information in each JWT allowing you to identify whatever you like (the user id in the database, the device id of whereve the user logged in from, etc). A JWT is essentially a datastructure allowing you to store information to be used by the API.
Some basics for how this works:
Getting the JWT into the app: A user logs in to the application using their username/password. The
api then returns an encrypted JWT to be used by the client for all future requests. Don't try to do
the encryption yourself. Any language that can handle serving an api
will have libraries for this.
Using information in the JWT: The JWT is itself a datastructure. For example, it might look like this:
{
user_id: 1,
device_id: 44215,
device_os: android,
}
Your api will decrypt the JWT when it is supplied for
authentication via the request header, and then have that information available in the
context of the session.
If you provide the language used by your api then I might be able to recommend a library.
I will conclude by referring to the final requirement you submitted which states essentially that you do not want to have to interview the user across installs. If I understand your meaning, that you want a user to be able to simply install the application and begin using it without supplying authentication credentials, then there is no way to achieve that securely. You might be able to come up with a hackish way to get it to work, but it will be fundamentally insecure.

Secure an API for mobile apps call

I've been doing a lot of search about secure my api for mobile apps for Android or IOS.
Almost all examples tell user provides an user id and password somehow in a exchange for a token.
But how to prevent someone else to consume my api without my consent?
Face the following scenario:
I expose an API,
I develop, then, an app for android to consume it,
I develop, then, an app for IOS to consume it.
Other developer performs a rev. engineer in my app, creates his own app and starts to consume it without authorization.
How to prevent that?
Short answer: you can't.
Little longer answer: If you know what you are doing you can always reverse engineer a given application and use its api. You can only make it more difficult and time consuming, using authentification via tokens and device ids or usernames is a good first step. Apart from that: why would you want to close your api to outsiders? If your server code is written well there is nothing to worry about.
You can maybe secure your API on a legal basis and sue developers who use it, but that is a completely different topic.
Some clarification regarding securing the API and securing content via the API. Assume you create a server where you can send user/password and receive a token if that combination was correct. For the account-page you send said token over and the server verifys that that token is valid and returns your account page. You secured the actual content of the API. That is obviously very possible and almost a must-have unless you have no user-specific data. But still everybody can send the exact same initial request from their custom app, sending a user/pass and again receive a token, etc. You cannot really prevent the request itself or even determine that it was not send by some service not authorized by you. You can send some hashes along the request to add some security by obfuscation, but since your app has to compute them, so can the reverse engineer.
Yes, login api are open but they return a token only on successful match in your database. You should focus more on security of your data than unknown hits at your api.
SignUp API can be used for creating a user, and login for returning token of that user. Only if malicious developer has credentials, then he can access tokens and auth APIs. There is also something about DDOS attacks so you can maybe write logic to temporarily block IPs where hits frequency is high.
You can also store device ID of signing user, which seems idle for your scenario. Entertain hits from that deviceID only. Similarly, user can add more devices with their credentials. I think even Google does that (generate alerts if user creds are signed in from new device and add the device to list if user confirms). Hope this helps.

Storing API key on mobile device

I've read many, if not all, answers to previously asked questions about the same topic, but questions themselves are not exactly about my case.
I have an OAuth 2.0 server running. It has an endpoint that provides access tokens to users. Programs and websites requesting the access token may or may not be owned by me, in other words, I may add a tool for website users and locate it on the same or neighboring website and my users may create an app and with their API key request access to user's data. Now I am developing the app that will operate user's data.
I realize that storing the API secret on the device is not a good solution. I have read about creating an end-point to which I make request directly from the app and then the endpoint makes API requests, but the endpoint will have to exist on the same host and probably server as OAuth server.
Is there a way to authorize mobile application to access user data when I am in controll of the application and the OAuth server? Should I create a separate end-point? Should I pass it device ID and/or any other information?
P.S. I know that plain old authorization would work here, but then what if some user wants to create his own mobile extension (not allowed currently for security reasons)? Also, current system has a button that is recognized by many people and they know what exactly will happen after clicking it. With the app, it may be an issue when the user sees a login dialog instead of the "Login with *" button. I really hope there is a clever solution to this.
Your concern is spot on. Your API Secret should not be stored on the device.
However, I am not sure why you would be concerned to build a separate endpoint, since OAuth 2 has a authorization flow for these use cases.
https://www.rfc-editor.org/rfc/rfc6749#section-9
In your use case, I'd suggest using the implicit grant flow to fetch the access token and store that on the local device. There would be no refresh tokens and the access_token can have an expiration date. Of course, the token on the device can be compromised, but the damage will be limited to a particular user and not the entire application.
If this level of security is not acceptable, then you can look at splitting up your API Secret in different parts of your app and then assemble it at run time in your app.

Can apps keep secrets?

A given server API should be publicly accessible to all unauthorized users, but requests should only be allowed to originate from one specific app.
This should, in theory, be accomplished by having the app HMAC-sign all API requests, and by having the server correctly issue and store nonces (to avoid replay attacks).
Question::
Are there any known methods for a mobile app to slice, dice, chop and XOR a secret, in a way that makes it extremely hard, if not impossible, for hackers and crackers to retrieve the key?
Create a free in-app purchase with iTunes connect and have users "buy" it (even though they won't be charged anything)... then verify the receipt with your servers... Apple will provide a transaction receipt which will verify that it originated from your app.
https://developer.apple.com/library/ios/#releasenotes/StoreKit/IAP_ReceiptValidation/

How can I manage in-app billing transactions on an external server securely?

I'm attempting to implement a system for upgrading/unlocking various features of my app using "managed" purchases with in-app billing, and I'm getting bogged down by the lack of in-depth documentation or examples.
My app's purpose is to retrieve/parse and display data from my own server, and the documentation on http://developer.android.com/guide/market/billing/billing_best_practices.html states:
If you are using a remote server to deliver or manage content, have your application verify the purchase state of the unlocked content whenever a user accesses the content.
My question is, what is the best way to go about this in terms of actual workflow?
As far as I can tell, on successful purchase I would store the purchase information on my server as well as locally in the app. When the app runs, I would send the order ID to my server and the server would check to see if the order is valid (firstly checking that the order exists in my server's database, and secondly checking if I have not manually revoked the order for whatever reason).
If that is verified, the server would send a response to the app that the requested features are "licensed", and the app would provide the unlocked features/content to the user.
The obvious problems I can see with this are:
A rooted user could easily just alter the local app's SQLITE database (or whatever other method I use to store order information) to inject a valid order ID.
If network access is down, or my server is down, I still want the app to be able to run (with cached data) with all the user's purchased features.
Potential ways around the first problem that I can see involve sending some sort of device identifier with the verification request, and monitoring that at my server's end - revoking the order if a large number of devices are accessing the order in a short period of time.
For the second problem, I can't figure out an adequate solution. I initially thought that each time the verification is successful, the time this verification took place would be stored. Then, the app would continue to run with the unlocked features for say, 48 hours after the last successful verification. The issue with that is, how can I securely store this time value? Again, rooted users could simply alter the value and the app would be none-the-wiser.
Has anyone designed a server-based system for managing in-app billing purchases and can offer some suggestions?
Google Licensing provides a way to allow a cached 'You're license is valid' response to stay alive.
Application Licensing
You can also encrypt the data your are storing. If they have paid for it, they get to decrypt it. If no network access available, then implement a similar caching scheme as Application Licensing (currently licensed under the Apache License, Version 2.0).

Categories

Resources