Authentication android messaging app - android

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.

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.

A "reasonable" security model for Android app and REST

We are getting started with developing an android app and the corresponding REST APIs and I need to figure out a security model for the same. I've close to zero experience with designing secure systems and would like some expert opinion on the loopholes of a first draft we've come up with.
I've been all over the web for the past few days and everyone seems to suggest HTTPS and OAUTH as the proven answer. Since our app doesn't deal with anyone's bank account, I think we can live with less than DoD grade security (although even they get hacked often!). And we don't want to spend the effort for OAUTH unless there really is no other reasonable alternative.
We're trying to avoid HTTPS because the app will, at times, be polling the server every few seconds and we thought it'd be too expensive to use it for all REST calls. Also, the payload for some of those API calls can be too big (2-4 KBytes) for asymmetric encryption.
Here's what we've lined up so far:
User creates an account by entering a unique 'username' and a 'password' on the registration page in the app
The 'username' is stored in plaintext in SharedPreferences using MODE_PRIVATE
The SHA-256 of the 'password' is also stored in SharedPreferences using MODE_PRIVATE
The user credentials ('username' and hashed 'password') are sent to the server using https://
The server creates an authentication "token" (a random AES key, really, using a CSPRNG), stores it in its DB and also sends it back to the client (using https, of course)
The AES-256 key is then stored by the app in the SharedPreferences using MODE_PRIVATE
All further communication between the app and the server is done over http:// with encrypted (payload (json/xml) + timestamp + checksum/hash) (CBC with random IV)
The AES key is only updated if the user changes his password
For actions that require additional security, the app asks the user to re-enter his password which is verified against the stored hash
The app should be usable offline (It can talk to pre-registered embedded devices over a WiFi connection. Security over WiFi is another story!)
I know some of the pitfalls of the system already:
Storing the key on the phone isn't safe: If a hacker gets access to the user's phone, the user just needs to change his password and everything will be safe.
Storing keys on the server is bad: A lot of people seem to say if you really have to store the keys, at least store them on a separate server. But that adds an extra round trip between the servers for every REST call. And there can potentially be many of them when the app is polling.
Keys without expiry are bad: I can't think of another way to let the app function offline.
The real questions now are:
What are the other loopholes that I've missed so far?
What kind of effort would it take for someone to break into the system?
Most important of all, how can we improve overall security to some "reasonable" standard without overdoing it?
This is not DoD security!
You really do need to use https and insure it is setup for TLS 1.2 and Perfect Forward Secrecy. Additionally the app needs to pin the certificate.
Section 1:
3: Do not use SHA256, use PBKDF2, crypt of another hash that has an increased work factor.
4: Send the password, not the hashed password to the server, the server does the hashing.
7: When using https there is no need to encrypt the payload, that is what https does.
Section 2:
2: When storing keys on the server keep them out of any http accessible directory. This is a weak point and needs to be addresses with server security.
Section 3:
Use two factor authentication for administration of the server. Have a good scheme to control the 2nd factor, I like hardware tokens and keep track of them by their serial numbers. That way there is a limited number and they can be recovered when someone is no longer should have administrator access. They can also be loaned for short periods of time.
You also need to have disaster plans for various contingencies, do not wait for an incidence and try to deal with it on the fly. Some times appropriate immediate action is required.
All of this is basic.
You need to evaluate potential threats, attackers and the value to an attacker or user.
If you care about security and are not a domain expert hire one for advice and review, I do.
Aside: DoD security: Two guard stations, two overhead passages between buildings, the last building has one door that is a huge safe door and there are no windows. Ceiling bubblegum lights rotating when there are un-cleared personal in the building, one escort per un-cleared person who follows you everywhere including into the bathroom, multiple sensors in the ceiling, tempest shielding.

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.

Securing Client / Server data. (Android)

I have read a few examples on SO for securing client / data. But we have a little bit different issue, and not sure where to look.
Basically we have an android game which is a geo-location based game. We use HMAC-SHA1 to the query string to verify that the data being sent from the client is in-fact from the client. There is a small issue. The HMAC-SHA1 key. I can obfuscate till my hearts content, but the key remains in the app. Someone can easily de-compile the app, grab the key, and then send manual queries by a browser for their user account (spoofing GPS).
I saw one example where someone suggested client & server side ssl authenication. Not sure how that would work, would you not just need to attach a ssl cert to the app? Would this not be subject to de-compiling also, it would require the end user to re-compile / use the cert?
Can we some how use the package manager to get the self signed cert? I need to find out the correct way to secure our transmission so someone can't fake their transmissions for their own user account..
Thanks
To authenticate the client, it needs some form of credentials. You can either:
don't save the credentials and have the user input them every time
save them somewhere
use system credentials
use some form of an identity provider
1 is inconvenient, 2 i subject to attacks as long as someone has physical access to the device. For 3, you could use the user's Google account so you can be (pretty) sure who they are and block them if there are any problems/attacks. 4 really a variation of 3: the user will authenticate to some third-party service and it will only issue an (temporary) access token. So if the account is compromised the token will eventually expire and/or be revoked (look into OAuth). Consider the risks and amount of work to implement and take your pick.
As for using client certificates, you can store them encrypted, so you need to provide a passphrase to use them. On pre-ICS you need to implement this yourself, on ICS you can use the system key store via the KeyChain API. You will only get access to the private key after you unlock the device (uses the unlock password/PIN to protect keys) and the user explicitly grants permission.
If you want to stick to you current way of doing things, implement the HMAC part in native code (OpenSSL, etc.), and generate the key at runtime by combining bits of it. That would make it fairly hard to reverse engineer. Additionally, you might want to add some sort of a nonce, so that requests cannot be replayed.

Securely submit data to remote server with 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.

Categories

Resources