2

I'm looking to build a mobile application (iOS / Android) that digests information from a secured API. The API will require OAuth2 authentication to be able to digest any resources. The service I'm providing via this API contains both information that is considered public, as well as information that requires an authorization scope by the end user. In an ideal world, only my official mobile app would be allowed to access the API, so I believe I need 2 different grants - one for the client (mobile app itself), and a second grant if the person using the app actually creates an account.

What I'm not exactly wrapping my head around is how to securely ensure that it's my official app that's requesting resources from the API, and not another program. The Implicit grant will work just fine for the second case, where I have a known user in the system. What kind of grant would I use for the first case, where I don't have a user to authorize access, but still want the client to retrieve information from the API?

  • I've been wondering this for a long time. But, after all the reading I've been doing, it seems bot to really be possible unless you do something like keep the MD5 digest of your compiled app in your API's database and check against that in every API request. But then an attacker could just take the MD5 as well. After all the reading I've done it seems like you just have to accept the fact that a determined attacker will decompile your app to find things like secrets. So honestly I don't know, but I would really like to see what experienced devs have done, as I'm just a noob. – Chris Cirefice Feb 19 '16 at 21:08
  • Chris I think that's also the point I've reached - either I'll have to accept part of my API as public, do short TTL's on a client_credential and have a means for the app itself to update that on a daily basis, or just wind up taking the risk that someone decompiles the app. – Joe Rieger Feb 21 '16 at 4:51
  • Hey Joe, I've given it a lot more thought and written an answer that may be of use. It's a bit long, but it covers different aspects of APIs that one has to consider in developing them. I hope that it's useful! – Chris Cirefice Feb 21 '16 at 5:41
0

I'm not very experienced in this area, but I will suggest a few things that I have learned and that I can prospect based on my readings, which should be taken with a grain of salt and researched a bit more before actual implementation.

API Questions to be Answered

Is your API meant to be completely public? Will you have multiple clients using your API (think of Facebook or Twitter)? Is your API entirely restricted (meaning only your 'official' app should be using it? Will users be authenticated in your API?

These are all question that need to be answered before continuing, because they will result in different architectures.

Completely public API

In this case, you are offering your API for general use and you should consider that spammers will eventually come along to take over your service. In this case, you should be worried about spam-bots and malicious end-users. There are several libraries in so many languages that aid with this. Consider googling anti-spam XXX where XXX is your programming language. Don't re-invent the wheel.

Keep in mind that even the best of libraries will only limit spammers in the most obvious of ways; this means that a determined attacker can DOS or DDOS your API if they really want to fight your anti-spam system.

"Official app" API

If your API should only be used by your 'official app' and no other clients (e.g. not the cURL utility, nor another programmer writing an app to interface with your API), I cannot really offer you any advice other than that again, a determined attacker will make his way in eventually.

I cannot vouch for high-profile targets like Twitter or Facebook as to what they do. My guess is that any public information that does not require authentication by user-specific credentials (e.g. a public profile page) will inevitably be spammed by bots or malicious users. However, these entities have sufficient scaling to handle such activity.

For your particular app, we had previously discussed very simple security techniques, such as taking the MD5 of your official app and using it in your API to 'authenticate' your app with the API server. However, an attacker could simply decompile your app and spam your server with the MD5, assuming they spent the time to figure out that your API required such 'authentication'.

Basically, the only way your API can know that your app is the 'official' app is if you store some secret in the app so that it can authenticate itself with the server. That could be some secret string, an MD5 of your compiled app, or even a request to some 'super secret' URL such as myapp.com/api/auth/mobile/android that would give the Android app an API key to use on subsequent requests. But, then an attacker could mimic the request from Android to get the same key.

I think you get the point. Preventing 'unofficial' apps from communicating with your API server is hard, and I honestly cannot think of a good way to prove the official app's identity, given that once an attacker has the binary package, they can decompile and sift through until they find what they need.

The same would apply if you had your 'official API clients' in your database (such as Twitter, Facebook, etc). Clients still need to use secrets and access tokens (with Oauth 2); so, theoretically, you could decompile just about any app that interacts with a 3rd-party API and use their access token and secret, impersonating their app. You can obscure your 'secret strings' all you want but, again, a determined attacker will find a way. Better to just build a system that can detect abuse and recover quickly!

Another term for this is Digital Rights Management, though in a slightly different context, and it never works! How hard you try to keep intruders out is up to your business constraints, really.

Per-user authentication

Now this is something I can actually answer!

If you ever have a user log in, even though a 3rd-party Oauth solution such as Facebook or Google login, always use TLS (SSL)! If you send usernames and passwords in plain-text, you may as well give up on securing your API because you failed the most basic step.

Once you have TLS set up, users should receive an 'API access key' per session. For a concrete example, I have the following architecture:

User has typical account information: username, password (hashed and salted of course), email, etc. A User will also be tied to an APIAccessKey in a 1:1 relationship. This means that a User will only ever have exactly 1 APIAccessKey associated with their account.

When a User authenticates (via any method), their APIAccessKey is regenerated and sent back in the API response. Any client using the API (e.g. Android, iOS, web, etc) should keep track of this access key. The next time a user makes an API request for a resource that should be restricted to only them, or scoped to them, they should send this access key in the request. The server will then validate it and respond accordingly or, if the access key is invalid, reject the response and ask for re-authentication.

How you determine whether or not the APIAccessKey is valid is completely dependent on your business constraints. For example, a government agency or bank would probably expire this access token in about 15-30 minutes. A social app would probably never expire the access token (have you ever been forced to log back in to Facebook in iOS/Android?).

But perhaps you see how this could be employed. You can also implement abuse protection per access token. For example, rate-limit requests based on the access token, such that if one token makes 1000 requests per second, you could reasonably believe that token to be compromised. Then, for all requests to that token that is now 'banned' (rate-limited), simply send the response reauthenticate: true or something similar. Any client correctly implementing your API will redirect them to the login screen. Once their token is regenerated, the attacker who had the previous token is now locked out of the API.

Multiple clients using your API

You should implement Oauth 2 for this!

This is essentially the exact same problem as per-user authentication. Anyone who wants to use your API should request an access token (and secret!) from you via a web interface or manual interaction with your support team, whatever you prefer. From there, you identify users via their API access token and can rate-limit them if need be. If their API token is compromised, you can simply regenerate it for them and the attacker will lose access in the same way as before.

This all works because users have a username or email and password, which should be completely unrecoverable by attackers in the most general sense. Attackers can intercept tokens mid-transit (man in the middle attack) or through other methods; but, if it changes, they can't do squat without knowing the password of the user who owns the token.

The best approach

The most secure approach would be to give each user who authenticates with the API an access token that regenerates with every request. This means that if a user sends a GET /posts, they must provide their access token. Their access token would then change during the GET request and be sent to them back in the response, which they would then use for the next request. An attacker who intercepts an access token will therefore only have it work for one request (that is, unless they are intercepting the TLS traffic and can decrypt it, in which case, whatever security measure you previously implemented is null and void).

Obviously this is computationally expensive; you're regenerating an access token on every single API request which could bog down your server(s), depending on your implementation. In any case, this should be a last resort and only used if you really need it. However, for forward-compatibility it might be worth setting up consumers (Android, iOS, etc) to use this schema, but for the meantime simply have the server send null for the value next_api_token (or what-have-you). That way, you don't have to force users to update to implement this schema if you really need to, and the integration will be seamless.


Hopefully all of this gave you some good ideas and will serve others in the future. It's a 'digital rights management' problem, none of which ever have a simple or straight-forward solution. All we can do is delay...

0

Can you use a client_credentials grant for the first type? It only requires the clientId & clientSecret in order to get a token. I believe it is meant to support application access, opposed to user access (where authorization is granted)

  • 1
    My understanding is that the client_credentials grant isn't appropriate. As you pointed out, it requires the id & secret, meaning I'd have to distribute the secret with each app that's installed. Anyone decompiling the installer could easily grab the secret and use it to gain access to the API. Revoking the key / secret in this case would then render all of the legitimate installs non-functional without a version update. – Joe Rieger Feb 21 '16 at 4:49
  • It sounds like you are more concerned about the risk of decomposition. Can you obfuscate that part of the application so that it's less obvious what the values are? OAuth2 on its own won't address what you're trying to achieve, I think. – EdH Feb 21 '16 at 5:22
  • This looks relevant to your investigations, especially the part about the clients... stackoverflow.com/questions/6190381/… – EdH Feb 21 '16 at 5:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.