Connecting to a webservice from an Android app securely - android

I am currently developing an app which downloads information from a webservice which I have written (in .net) and I want to secure the connection so that only my app can get data from the service. What is the best way of going about this?
I don't want anyone to be able to get the access details if they decompile/reverse engineer my app. Is there a way I can verify the integrity of the app that is requesting data before sending it back?
I don't care about them being able to sniff the traffic to see what it contains, I just don't want anything other than my app to be able to submit requests to protect against anyone scraping all of the data.
I'm very much a newbie in security so a simple as possible please!

Chris,
You can read on a mechanism called One Time Passwords (OTPs).
http://en.wikipedia.org/wiki/One-time_password
You can design your application to generate OTPs whenever it tries to connect to your web service. The responsibility of validating the authenticity of the OTP resides on the web service.
Let me go into a little detail now. Imagine that your app embeds in it an algorithm which generates and supplies a 256bit number whenever it connects to the web service. The web service you design also implements the validator part of the OTP. Usually OTP algorithm takes into account "Time of the day" in its implementation (I suggest google around for some Free implementations). So the server end (OTP Validator) only works if the time on Server and client is within a window (say +- n sec) of the refresh time n. Typically, the OTP validator will also generate the OTP on its end and just compare the received one. You can additionally HASH the OTP before sending and compare the HASHes of generated OTP on the server(Doesn't help or is any more secure though).
Now the question arises, what if someone gets the algorithm (may be you just use an open source OTP). Well, its meant to be. A good security implementation is only accessible with correct password, even if everything else is available to attacker. To make this, you may have to add a logic to provision your apps the first time they connect, which OTP would expect. Here I assume trust on first use. You may add some logic to store a unique resident app id that is used while calculating the OTP. Additionally, you will have maintain a mapping of "resident-id" to "public-id" on server. It is the "public-id" that you may attach to OTP and send to server to validate the app sending is indeed the one you provisioned. This requires you to map "public-id" to "resident-id" on server and then use the "provisioned-id" the same way in generating the OTP.
On top of this, you can add logic to just entertain the OTP+"public-id" combo once. This shall prevent the replay attacks in case someone just sniffs and re-sends the same request to your web service.
Hope this gives you some idea.
Ujjwal

Related

How to avoid interceptions of the connection to the server in Android?

In my Android app, I am getting the user information from server using a HttpURLConnection. Each user has a unique Id which may be accessed publicly.
Problem is if a third party, say, UserB has the Id of UserA, then they can abuse it by setting it inside my app (we know that how easy is to decompile Android APKs) then calling the server using my app and getting the output from server (including sensitive private information of UserA).
How can I prevent this from happening? What security tricks do you recommend?
Side note 1: I already have used encryption/decryption methods. But they are not going to stop UserB from abuse because when the UserB sets the Id of UserA, the app calls the server and then they have access to final decrypted output.
Side note 2: I have thought about Phone Number verification, but it is not operational for my app currently.
Side note 3: I cannot restrict the user to a specific device because they have to be able to use it on their different devices.
Side note 4: Libraries like Firebase, Gcm and the like are so secure. It would be a good idea to find out what ways they use to keep hackers from accessing another user's information!
Side note 5: Thanks to Gabor, I noticed that I had to mention that I cannot use a login interface unfortunately. If I could, that would be for sure a primary choice. It's the nature of my app and I can't change it!
That's actually a very good question and a holy grail of all security officers :)
What's I learned is that whatever you do, as long as you cannot protect the physical device against unauthorized access, there's always a risk. The problem is:
* On the one hand, you wish that the app will keep and store an information which authorizes the owner of the device
* On the other hand, you have to protect this information on the device, but because your app needs to be able for accessing it, also the accessing algorithm must be available on the device.
So I would say, there's no "clear" way. What you can do, is to make the cost of obtaining information (in your case) unprofitable.
You said that the user ID is "publicly available". That's ok, but it means that the UserID is not "secure information". I would say, that your users need to be authorized first, and then the server should generate a UNIQUE token, that will be used in replacement of UserID when calling next requests.
You can implement it in many ways, but I will recommend one way, that should be not complex for your users:
Let's assume that all your users are registered. During the registration, each user needs to provide his email, UserID (could be generated) and password. Note that registration could be done in the mobile app or on the web portal.
When the app is going to start for the first time, a user should provide hist UserID (or simply email) and password.
With the first call to the server, the userID and password should be sent to the server, and server generated a Token (unique for every first login so even if the user will use two or more mobile devices each one will use the new token).
With every next call to the server, only the token needs to be provided to authenticate the user/device.
Where to store that token? No matter. I would say in any private storage of the app. You can and should, of course, encrypt it, obfuscate a so one, but whatever you do, if one has access to the device, he can always copy it.
You will say now, that it's not 100% secure. That's right. So I would say if it could not be secure, we should minimize the risk of abuse.
There are also some ways how one can do that.
First of all, in case of abuse, your users should be informed about it. Having a token algorithm, the user can take and action, and simply disable stolen tokens.
In case if the device has been for instance stolen, your users can/should be able to disable tokens (devices) on the web portal (or in another instance of the app) after signing in using email/password authentication.
The only one problem is how to detect that the mobile device has been "cloned". In that case, the user is physically not aware of the abuse.
My guess here is to implement the following algorithm (auth pooling):
1. Let the mobile app send the "keep alive" message with the Token to the server at the certain time when the app is inactive (let's say user xyz#gmail.com should send keepalive always at 10:00, 12:00 and so one).
2. Let the app send the keep alive, with some frequency when the user is logged in (app is active).
3. These frequencies/schedules must be know for the server and app (and could be even public).
In case if the server detects the same token in keep alive nearly the same time, the user should be informed (by the different channel, it could email) about possible abuse.
* NOTE: this is only an idea, I never did that, and I'm also wondering what other things about it, but in my opinion, this is quite simple to implement, and gives you a good change to minimize the risk.
When a user starts using the app, they should log in using their credentials (eg. username and password). From the app's perspective, this is a roundtrip to the server to obtain a token. The token is then stored in the appropriate credential store for the platform you are using, and can be used to impersonate the user in further requests (the token can be sent with requests as for example an Authorize header, practically a bearer token). It also should have an expiry time, after which the user has to provide his credentials again.
Such a token can be a plain jwt you create, or it may come from something like a full oauth2 / openid connect implementation. If you decide to implement it yourself, be careful, it is not straightforward to get it right.
This way, you have proper authentication in place, you know who your users are in subsequent requests, and this way you can enforce access control rules on the server.

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.

Android: verify legitimacy of a user server side

I have an app that retrieves data via http from a server. App sends a POST request with some variables to execute the query and retrieve the data in a JSON format.
The problem is I don't find a way to make the data secure into my server (only accessible to users that have MY application installed). If someone gets my app, and decompile it (even ProGuard won't avoid this for too long) a modded app could start sending requests to my server, using exactly the same protocols, parameters and IP address.
So, in a nutshell, the question is: Is there a way to check (server side, of course) if a request is coming from a legit user?, any way to check if the requester is using my app and not a modded one?
PS: I've been looking for questions like this one and only found another close one that suggested a "user login" approach as answer. I don't want to bother my users with any login mechanics.
Thanks in advance.
Google offers a method to verify back-end calls from an Android app as part of Google Play Services which allows you to verify that the back-end call came from your signed application. One advantage that it has is there is no user login required to verify calls due to the client ID scope used to get the auth token.

Verifying that message came from a specific app/end point

I'm trying to build a secure system for transmitting data from a client Android app to a web server running PHP.
What I want to do is ensure that the system is cryptographically secure in such a way that the messages from the app can be verified as being actually from the app itself, rather than being from a devious user who may have written a custom script or perhaps using cURL in order to game the system.
There are a number of use cases for this kind of verification, for example:-
If an app contains an advert from which you gather metrics, you would want to verify that the click data is being sent from the app rather than from a malicious user who has figured out your API and is sending dummy data.
The app might have a multiple-choice survey and again, you would want to ensure that the survey results are being collected from the app.
The app is collecting GPS traces and you want to ensure that the data is being sent from the app itself.
In each of these cases, you would want to ensure that the origin of the messages is the app itself, and not just a user who is running a simple script to fake the data.
Some ideas I've considered:-
SSL - Works well for securing the channel and preventing tampering (which fulfils some of the requirements) but still cannot ensure the integrity of the source of the data.
Public-key cryptography - The client app could encrypt the data with a private key and then transmit it to the server where it can be decoded. The problem is that the private key needs to be hardcoded within the app -- the app could be decompiled and the private key extracted and then used to send fake data.
Home-made algorithms - A very similar question to this is asked here where the solutions only work until "someone figures out your algorithm" -- i.e. not a great solution!
Hash chain - This seemed like a really interesting way of using one-time keys to verify each data payload from the client to server, but again it relies on the app itself not being decompiled, because the password still needs to be stored by the app.
My limited knowledge of cryptography makes me think that it's actually theoretically impossible to build a system that would be totally verifiable in this manner, because if we cannot trust the end client or the channel, then there is nothing on which to base any trust... but maybe there's something I've overlooked!
It's not that hard, you just need to authenticate the app. You can do this with a simple user and password (over SSL) or use client authentication. In both cases, the credentials need to be in the app, and an attacker can extract them and impersonate the app. You have to leave with it and maybe implement some methods to mitigate it.
You can also authenticate the messages, by having them signed either with an asymmetric key (RSA, etc.) or a symmetric one (HMAC, etc.). A nonce helps against replays, where someone captures a validly signed messages and sends it to your server over and over again. Depending on your protocol, the overhead of using one might be too much.
To protect the credentials, you can have the client generate them and save them in the system KeyStore, although it is not quite supported by a public API, see here for some details. This, of course, requires an extra step where you need to send the generated credentials (say, public key) to your server securely which might be tricky to implement properly.
Whatever you do, don't try to invent your own cryptographic algorithm or protocol, use an established one.

Verify Android user is human (without a CAPTCHA)

I have an app where users can add ratings, and I don't want them to have to register to do it, but I also don't want it to be easy for bots to game the ratings.
Is there a way I can be reasonably (doesn't have to be 100%, but I don't want to use reactive heuristic methods) sure that my users are human? Without requiring any kind of CAPTCHA / sign-in / other action. Normally I would say that this is impossible, but since my app runs on Android I think we can do better than nothing.
Gmail address.
My first thought was to get their gmail address from AccountManager, but I can't see a way to verify that they own that email address - i.e. a bot could just send made-up emails to my server, so I don't think this can work (and I don't want to make them authenticate my app using their google account; they are unlikely to do this).
GCM
My next thought was to use Google's Cloud Messaging thing. I can get a cloud messaging ID from the device, send it to my server, send a random cloud message from the server back to the device, and send that message back to the server. I think this at least verifies that they do have an Android device with a gmail account, which is good enough.
SMS
Of course I could send them an SMS, but that costs money and to be seamless means that I need to have permission to read their messages, which I'd really like to avoid (especially as the rating is an optional feature).
Android Licensing Server
Maybe it is possible to use the Licensing Verification Library to get a signed assurance from Google that the user downloaded it from the market, but due to the nature of my app I can't put it in the market.
Device ID, EMEI, phone number, etc.
Of course I can't use these. Bots could just make them up!
So GCM looks like the best (and only) option. Can anyone think of anything else?
Show some popups randomly and place their close buttons at different place, so user has to close them.
OR
Using drag drop API ask user to drag and drop button into some area on screen and then submit rating. You can randomize placing of button.
There could be multiplaces where you can drag button but you can instruct user to put in the right one.
As you control both sides of the communication, you could do something like this:
Flow
App: Request one-time secret token from server.
Server: Create one-time secret token and a tracking-id and send both to the App, while keeping track of the secret token by using the tracking-id.
App: encrypt the voting using the one-time secret token (see below about encryption)
App: send encrypted message and tracking-id to server.
Server: Find secret token using tracking-id, make sure it hasn't been already used and decrypt the voting using the secret-token.
Encryption
You can use any symetrical encryption technology. A very simple example would be to XOR your message (i.e. voting) with the secret-token on the App-side. On Server-side XOR-ing again with the same secret-token gives the plain message again.
This method is safe as long as your method of encryption is not known to the attacker. If it is known of course he can just simulate the requests the App does, but it would hold true for every method, so you probably should use something better than simple XOR-ing.

Categories

Resources