14

I've been developing an application which will support many users. The thing is I'm unable to figure out, how to authenticate the client/user.

I'm building an app like http://quickblox.com/ where I'll give credentials to my users and they will use those to build N applications in which they can't put their username and password to get authenticated.

Let's assume it goes as follow. (Just like QuickBlox)

1. User creates account on my website.
2. User can create N API keys and secrete credentials. (For multiple apps)
3. User will use these credentials in their applications (Android, iOS, Javascript etc...) to talk with my REST APIs.
(REST APIs have read and write access.)

My concern?

Users will put their credentials(API key and secrete key) in applications they build, what if someone get these keys and try to mimic the user? (By decompiling APK or directly looking into JavaScript code.

Am I wrong at somewhere?
I'm confused to architect this three level user mechanism.

  • The thing you seem to be trying to do is not possible. – immibis Aug 2 '16 at 4:02
  • There are many applications out there which does the same thing. I'm not sure how do they authenticate the users. – Alok Patel Aug 2 '16 at 5:19
  • Are you trying to authenticate the client application, or the user? Lots of apps authenticate users. None of them authenticate client applications in an unbreakable way. – immibis Aug 2 '16 at 5:20
  • Yeah by client I mean I want to authenticate the user only. – Alok Patel Aug 2 '16 at 5:24
  • 4
    Oh, well then in the most typical authentication system, you just get the user to enter their username and password, and send them securely to the server which checks them and (securely) returns a session token, and then you send the session token in every future request. – immibis Aug 2 '16 at 5:25
6
+50

I have been designing REST APIs for the past few years. You are worrying too much. Recently another user on this board has asked a question, where he was worried about storing URI endpoints in his JavaScript client-side code.

Same rules apply to you as apply to the JavaScript developer. If you allow people from the outside to integrate your API, your API has the same visibility as a regular website and you should treat it the same way.

Quote from the original answer:

When you are creating a website and you do not want users to do something, you do not implement that functionality or forbid certain users from using it. With a REST API which should have public endpoints it is pretty much the same, you need to treat it like a public website.

Your REST API should be robust enough not to allow invalid operations, such as access to data from a different user.

You should design your application access tokens to only allow operations which you want to be allowed. You could have two types of access tokens:

  • master token: could be used by the application creator and provide more functionality from your API,
  • application token: the token which would actually be stored within the applications and would have only limited access to your API, only to operations which cannot corrupt yours or the application programmer's data.

But what someone deconstructs the source code, takes the tokens out of the application, finds out what the public endpoints are and abuses your web service?

Unless you are directly managing the development of the applications consuming your API, nothing really prohibits people abuse your API the same way directly from the app.

  • Good explanation so far, I've a question though. Let's say one of my API is build to fetch all the related data (A+B) of my user. My user use this API in his app to get the filtered data (B) of his user only. Now is it possible, or is there any workaround to prevent third user to steal all the data (A+B) of my user. Does it make sense? – Alok Patel Aug 4 '16 at 17:22
  • @AlokPatel There's no other workaround then to simply not implement the functionality. When you do so, there's always the risk of someone spoofind his identity hash to look like someone else. Programmatically your problem cannot be solved. As I have said, if you do not want to offer some functionality, do not implement it. Since the apps will likely store the login hash within them, once the app is deployed, so is your API key and it's not publicly available. – Andy Aug 4 '16 at 18:15
  • Thanks for the explanation. So What I got so far is REST APIs are same as any website we deploy they are as open as website. If I don't want user to do something then I simply don't implement it in my REST APIs. So what I can do is to have separate keys for client libraries (Android, iOS, JS) which can be compromised with less functionality and different keys which will be used server side (PHP, Java, node.js) with extended functionality. Hope this will work! – Alok Patel Aug 5 '16 at 5:28
  • Can you explain me your this point ? Unless you are directly managing the development of the applications consuming your API – Alok Patel Aug 8 '16 at 3:37
  • @AlokPatel What I meant is, right now you are worrying that you give someone access to the API, they may distribute the access and start abusing the API. If you have no control over the development of the applications consuming your API, they might do the same even on their own. – Andy Aug 8 '16 at 7:21
5

Your problem is not a technical one so much as a business one.

Lets say you have your API, which you sell to your customers (the app developers) for a flat rate of £100 a year, unlimited access.

Well then obviously, I can buy your service at £100 and sell it on to 10 people at $50 each. You don't want that! so you try to think of a restriction that will let you sell your API without it being open to arbitrage.

  • If you just restrict the number of Apps, a customer can create a single app which accepts connections from other apps and passes them on.

  • If you limit the users, again, the customer can hide users behind his own authentication and appear to be a single user.

What you need to do is pass the cost of each API call on to your customer. ie charge per API call, or set a quota of calls per year.

This pushes the same problem of arbitrage onto your customers. It forces them to put in place measure to prevent their users from stealing their keys. In this case, hiding your api behind their own user authenticated api.

  • I've already planned to limit the usage of my API based on number of API calls so business related problem is not my concern at the moment, I'm only concerned about keys getting stolen. – Alok Patel Aug 4 '16 at 17:08
  • From business point of view, the problem is unsolvable. Sadly, you cannot solve it programmatically either. – Andy Aug 4 '16 at 18:11
  • 1
    The business proble .is solved by charging per call. If the key is stolen your customer loses out. Not you. Just give your customer a way to cancel stolen keys and say its up to them to have an intermediate api to prevent abuse – Ewan Aug 4 '16 at 19:11
2

The other answers all seem to suggest that the problem of storing a secret in an app on consumer devices is not solvable.

Sure it is.

Two principles (the implementation details will follow):

  1. The actual authentication end points need to be anonymously open to the public.
  2. The server must somehow be involved in authenticating the client and providing an API key.

Given that, if the client makes a request to the authentication end point with credentials, and the server authenticates it, the server can generate a dynamic temporary token (temporary meaning time-based). This token should be remembered within the client and sent with subsequent requests.

You'll need a mechanism to periodically "refresh" the token, meaning, get a new one. Just build a REST endpoint that allows for generating a new token from an existing one, to avoid having to re-authenticate from credentials.

If you are trying to avoid the end user re-authenticating themselves, then this authentication can be an initial one-time setup in the app when it gets installed.

This solution simply avoids the need to store a static token embedded within the application binary. A token is generated on-the-fly by the server only in response to a successful authentication. For a malicious user to inspect your application and try to get unauthorized API access, they would still need to authenticate just like anybody else.

  • Interesting solution, though it mostly relies on how the OP's clients will code their app. This said, the proposed approach could allow then to store the API key server side and following successfull authentication of their own users could forward the temporary key for the actual app to use. this way nothing gets stored in the app itself. – Newtopian Aug 8 '16 at 13:55
  • That is true of all API's. If an API consumer does not consume it properly, things may not work. This would have to be a documented part of the API. – Brandon Aug 8 '16 at 16:22
  • By the way, there are standards to help make this easier, like OAuth. – Brandon Aug 8 '16 at 16:22
0

If you have unique per-app keys you could use those only during an initial connection authentication, initiated by the client, after which you switch to a rolling per-app unique authentication token.

Your server changes (rolls) the token for each client app from time to time (periodically plus/minus some random fuzzy/random delay, for example). The rolling token is only known between by the server and the authenticated client.

The new tokens are returned piggy-backed on the regular replies. Whenever the reply contains a new token the receiving app needs to switch to using it in subsequent requests.

Whenever the exchange with a client gets out of sync (some protocol error of some sort) your server will request re-authentication (through an error reply to the next client request, or piggy-backed on the valid response to the client request, for example).

Initial authentication initiated by clients while a rolling token is actively used should be regarded with suspicion - it could very well be a mimicking attempt. I'd only allow it if the exchange goes idle for a longer-than-expected interval, which could, for example, be caused by a client outage/restart with a new instance which doesn't have the rolling token.

It would be even better to persist the token on the client side such that a restarted client can continue from where its predecessor left - significantly narrowing the opening for mimicking.

Such scheme would make mimicking at least quite difficult - the mimicking client would have to predict exactly the window when the authorized client stops sending requests long enough for the server to decide it's OK to accept a new client authentication with the prescribed key can take place. Such requests outside of the allowed window can be used as detection of mimicking attempts and possibly initiate some countermeasures (IP blacklisting, etc).

0

From what i know, what you mentioned is the only way to do this. The application storing the key is definitely a risk, but there are various ways to circumvent it. You can always use the keystore to store the key, than hardcoding, thus forcing a one time login.

Also, you should consider binding a key to a client, thus, if someone mimics, you should have a security layer to check the client, the key and user agents to block the request immediately. Have a use case to re-issue or re-assure that the keys are not mimicked.

  • What is work around for JavaScript? How to architect for that? – Alok Patel Aug 4 '16 at 6:17
  • I am assuming you are talking about creating a hybrid application. If thats the case, then definitely you should be able to create a plugin to store the keys. If you are going to host the application and talking about mobile web solution, then think about rendering the page using a container and you can rely on a session token suggested earlier – Arun Aug 4 '16 at 7:21
  • No it's not the case. I would be the third top API provider, my users will use my API service in their applications. It can be Android, iOS, JavaScript etc... – Alok Patel Aug 4 '16 at 17:11
0

If you depend upon giving authorisation tokens to your customers to put in their apps, it will always be theoretically possible for someone to reverse engineer the app and extract them. To prevent this you would need a mechanism that would not require a secret within the client app. That is tricky. I can suggest some options for you to think about though.

You have a problem once you have given out the credentials, you have no control over how securely they are stored. Also, if you require the user to send the credentials to you then someone can MITM your connection and steal the tokens directly without bothering about reverse engineering the app.

One way of making it more difficult to extract your authorisation token is to obfuscate it. This just raises the bar, but doesn't make it impossible, and to do that you would have to retain control of the secret. You could implement a library that contains the secret information and is specific to each customer. You could use the library to communicate with your servers and you might not even have to tell your user the secret information, it could just be embedded in the library. This does not solve the problem of someone reverse engineering your library, but it does put you in control of the level of obfuscation. A drawback is that once one person has broken the obfuscation in the library, they can attack any library of yours, unless you write code which makes each library significantly different. That introduces its own set of problems.

This may stray slightly from the scope of your question, but it is related to the security of your token so I will mention it. To prevent trivial theft of the token over the wire, you probably don't want to send the token directly, instead you could sign the traffic using an HMAC function. You can check the message validity by calculating the HMAC of the message on the server and comparing it against the HMAC sent from the client. You would use the token as the key to the HMAC function so only someone who knows the token can sign traffic. This is better for the security of your token because you never send it directly to the server so it cannot be intercepted and stolen directly. For more information on HMACS see this question: https://security.stackexchange.com/questions/20129/how-and-when-do-i-use-hmac/20301

No security solution will be impregnable, you have to decide how much it will cost you to implement vs the likelihood and cost of being compromised.

  • I can't make a library and put secretes in it, those will be different for each of my user. – Alok Patel Aug 4 '16 at 17:15
  • To clarify, I was suggesting you could build a custom library for each of your users and hide their individual secrets inside the library. You would need to write a system to generate the libraries automatically on demand for each new user which may be more work than you want to do. – ThePragmatist Aug 5 '16 at 8:17
0

Quoting yourself:

I'm unable to figure out, how to authenticate the client/user ... in which they can't put their username and password to get authenticated.

Now that's a bit of a contradiction, isn't it? ;)

As others said, you can't. If an App uses an API key, one can decompile it as you say to get the key(s) and use it too.

Other than requiring additional proper user authentication, you can only limit the damage:

  • whitelisting / blacklisting IPs
  • throttling
  • "unusual activity" detection and its source
  • easy key renewal

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.