Securely submit data to remote server with Android - android

Bit of a niche question really. When I say "securely", I don't mean SSL.
Basically I've been working on adding C2DM push messaging to my app, and on my test bed, this all works fine and notifications are received. I was following this guide:
http://blog.mediarain.com/2011/03/simple-google-android-c2dm-tutorial-push-notifications-for-android/
Now I'm all fine with that and I fully understand it, my problem is the passing of the device's unique ID to my web server which is forwarding the messages. Say for example that in order to add the device ID to my database of IDs to message, it makes a call like so:
http://www.example.com/add_id?id=unique_id_here
Which inserts that ID into my database, adding it to the list of devices I have available to push messages to, what's to stop someone just visiting that URL and filling my database with crap by submitting fake IDs? Is there any way I can verify the data I'm receiving there, or verify the connection is coming from my app?

Note This is now edited for a much more obvious answer; my original answer is at the end, in case anyone finds the ideas useful
This is actually pretty simple. Send the message as a POST, and provide some form of digital signature with it. This could be as simple as an MD5 hash of the (message+secret). When you receive the POST, perform the same hash, and if the hashes match:
It came from your app
It came from someone reverse engineering your app
Sadly #2 is impossible to rule out completely, all you can do is obfusticate code to raise the bar, and monitor the server for suspicious activity.
The old answer
In principal nothing; networks & handset manufacturers generally make sure a specific device doesn't send identifying headers, because of privacy concerns and laws. Even if these were present, they could be faked.
You'll need to authenticate a client somehow. This can be done in one of several ways:
per-device unique username/password as a one-time config by user.
per-device unique ID distributed via SMS (requires device phone number, and SMS permissions for app)
per-device unique ID via License Manager APIs (not investigated, but almost certain to exist, as each client is individually licensed)
I'm assuming the fake data is only an issue if it's associated with the wrong device, and someone corrupting their own data is odd, but not problematic.

You can always pass some HTTP header with your request. Bathic Auth or just string known to you only

#peter For the #2 condition, I think you could compile a .so library with JNI(java native interface)+javah, you could call it to get the device id and a token that was encrypted with a specific method, and verify the two on your web server.
I think a .so native shared library is more difficult to decompile to get the encryption method.

Related

Authenticate Android application requests

I want to develop an Android application in which anonymous users can send requests to my server through HTTPS. I need to make sure that the requests are coming from my app since anyone can craft an HTPP request and send it. This is very critical in my app.
I read about GCM tokens, but I don't know if they can help me in my issue.
Is there a way to authenticate the requests (coming from the app) without hiding secret keys in code (because I read that hiding secrets is a bad practice as de-compilation is very trivial in Android).
Thanks
You can always generate a unique token for your user. And add that token in the header of your request and verify it on your backend.
Your server could generate unique PIN for each user of your app and it is then sent to your app and displayed over the app.
Users, even though anonymous, are supposed to enter the same PIN before sending the response. In turn request could carry this PIN that server can verify that indeed it has come from the same app.
Further you can set timeout for validity of each PIN is valid so that it is not mis-used and always latest PIN generated are used at the end of any session.
One question further to be answered related to point 1: Is how to ensure that this PIN is sent to your app and not to any fake app.
Answer to that will be : For this every app will get unique applicationid when installed on android device. While installation, this applicationid could register with your server in a discreet manner. So this way you ensure that all your API calls are coming from registered app.
I figured out how to solve this issue after following this guide: https://android-developers.googleblog.com/2013/01/verifying-back-end-calls-from-android.html
Basically, You use the GoogleAuthUtil class, available through Google Play services, to retrieve a string called an “ID Token”. You send the token to your back end and your back end can use it to quickly and cheaply verify which app sent it and who was using the app.
When your server receives the token from your Android app, it’s really important that you verify it. This requires two steps:
Verify that it’s really signed by Google.
Verify that it’s really meant for you.
Thanks.

Authentication android messaging app

This is a messaging app. It has no login (username or password). This means it has to send messsages to a server, and the server must trust it is coming from the phone number it says it is coming from.
How do you do that?
1) Send token to phones with text message service
Unfortunately, you're not going to be able to guarantee with 100% certainty that the phone number reported to the server is the one it's coming from. The reason is that the client code can be reverse engineered, regardless of what you do. There are some things you can do however to make it a little more difficult, although it is important that you don't depend on this to be 100% secure. If you need 100% assurance, then you need to have the app authenticate to the server through traditional means.
The way that I would do this, is embed a token in each copy of the client that gets released, such that each client has a different token. The token should have extremely large entropy (such as a 128-bit or greater integer), and you should keep a list on the server of tokens you've issued with the phone number of the device, so you can check them for validity. Require re-installs of the app to use a new token, and blacklist the previous token so it can no longer be used. The UID can be used, but be advised that it can easily be spoofed by a rooted device.
Submit this token to the server each time and ensure that the phone number the app claims to have never changes. To make it harder for reverse engineers to find the token in your code, you can xor it one or more times with additional tokens, and you can also lay out a bunch of fake tokens throughout the code that are blacklisted on the server.
You can also encrypt it with a secret key that is retrieved from the server so that the embedded token must be retrieved by an RE during live interaction with the server. Again this in no way guarantees that the token won't be found and changed/stolen, but it raises the bar for potential reverse engineers.
To prevent someone from sniffing the wire and obtaining and/or tampering with your token, or from using a proxy like Burp Suite to capture/tamper with it, you should use an encrypted HMAC. If you've never used an HMAC before, be advised that unless you encrypt it, it only provides authentication and integrity, not confidentiality.
EDIT:
Should also add, that you should run your code through an Obfuscator before you deploy it. This won't obfuscate the token, but it will obfuscate the decompiled code so it looks like gibberish to the RE. This forces the RE to use the byte code/assembly code from your app, which is much, much harder.
Associate each phone number with a unique device identifier
Get the udid and send it with each request
Create a signature that follow each request to your server. The signature shoukd be something like: secret key1+msg+phone number+udid+secret key2, then SHA1 the string and attach to th request.
On server calculate the signature and compare to original that followed the message. If they match, ok, else don't send it.
Use strong keys, and use two, to make brue force extraction, almost impossible.

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.

Connecting to a webservice from an Android app securely

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

Categories

Resources