OAuth secrets in mobile apps

37,261

Solution 1

Yes, this is an issue with the OAuth design that we are facing ourselves. We opted to proxy all calls through our own server. OAuth wasn't entirely flushed out in respect of desktop apps. There is no prefect solution to the issue that I've found without changing OAuth.

If you think about it and ask the question why we have secrets, is mostly for provision and disabling apps. If our secret is compromised, then the provider can only really revoke the entire app. Since we have to embed our secret in the desktop app, we are sorta screwed.

The solution is to have a different secret for each desktop app. OAuth doesn't make this concept easy. One way is have the user go and create an secret on their own and enter the key on their own into your desktop app (some facebook apps did something similar for a long time, having the user go and create facebook to setup their custom quizes and crap). It's not a great experience for the user.

I'm working on proposal for a delegation system for OAuth. The concept is that using our own secret key we get from our provider, we could issue our own delegated secret to our own desktop clients (one for each desktop app basically) and then during the auth process we send that key over to the top level provider that calls back to us and re-validates with us. That way we can revoke on own secrets we issue to each desktop client. (Borrowing a lot of how this works from SSL). This entire system would be prefect for value-add webservices as well that pass on calls to a third party webservice.

The process could also be done without delegation verification callbacks if the top level provider provides an API to generate and revoke new delegated secrets. Facebook is doing something similar by allowing facebook apps to allow users to create sub-apps.

There are some talks about the issue online:

http://blog.atebits.com/2009/02/fixing-oauth/ http://groups.google.com/group/twitter-development-talk/browse_thread/thread/629b03475a3d78a1/de1071bf4b820c14#de1071bf4b820c14

Twitter and Yammer's solution is a authentication pin solution: https://dev.twitter.com/oauth/pin-based https://www.yammer.com/api_oauth_security_addendum.html

Solution 2

With OAUth 2.0, you can store the secret on the server. Use the server to acquire an access token that you then move to the app and you can make calls from the app to the resource directly.

With OAuth 1.0 (Twitter), the secret is required to make API calls. Proxying calls through the server is the only way to ensure the secret is not compromised.

Both require some mechanism that your server component knows it is your client calling it. This tends to be done on installation and using a platform specific mechanism to get an app id of some kind in the call to your server.

(I am the editor of the OAuth 2.0 spec)

Solution 3

One solution could be to hard code the OAuth secret into the code, but not as a plain string. Obfuscate it in some way - split it into segments, shift characters by an offset, rotate it - do any or all of these things. A cracker can analyse your byte code and find strings, but the obfuscation code might be hard to figure out.

It's not a foolproof solution, but a cheap one.

Depending on the value of the exploit, some genius crackers can go to greater lengths to find your secret code. You need to weigh the factors - cost of previously mentioned server side solution, incentive for crackers to spend more efforts on finding your secret code, and the complexity of the obfuscation you can implement.

Solution 4

Do not store the secret inside the application.

You need to have a server that can be accessed by the application over https (obviously) and you store the secret on it.

When someone want to login via your mobile/desktop application, your application will simply forward the request to the server that will then append the secret and send it to the service provider. Your server can then tell your application if it was successful or not.

Then if you need to get any sensitive information from the service (facebook, google, twitter, etc), the application ask your server and your server will give it to the application only if it is correctly connected.

There is not really any option except storing it on a server. Nothing on the client side is secure.

Note

That said, this will only protect you against malicious client but not client against malicious you and not client against other malicious clients (phising)...

OAuth is a much better protocol in browser than on desktop/mobile.

Solution 5

There is a new extension to the Authorization Code Grant Type called Proof Key for Code Exchange (PKCE). With it, you don't need a client secret.

PKCE (RFC 7636) is a technique to secure public clients that don't use a client secret.

It is primarily used by native and mobile apps, but the technique can be applied to any public client as well. It requires additional support by the authorization server, so it is only supported on certain providers.

from https://oauth.net/2/pkce/

For more information, you can read the full RFC 7636 or this short introduction.

Share:
37,261
Felixyz
Author by

Felixyz

Fat Agnus hacker grown up to become logic programming advocate and domain modeling aficionado. I host The Search Space podcast (http://thesearch.space/)

Updated on July 19, 2020

Comments

  • Felixyz
    Felixyz almost 4 years

    When using the OAuth protocol, you need a secret string obtained from the service you want to delegate to. If you are doing this in a web app, you can simply store the secret in your data base or on the file system, but what is the best way to handle it in a mobile app (or a desktop app for that matter)?

    Storing the string in the app is obviously not good, as someone could easily find it and abuse it.

    Another approach would be to store it on your server, and have the app fetch it on every run, never storing it on the phone. This is almost as bad, because you have to include the URL in the app.

    The only workable solution I can come up with is to first obtain the Access Token as normal (preferably using a web view inside the app), and then route all further communication through our server, which would append the secret to the request data and communicate with the provider. Then again, I'm a security noob, so I'd really like to hear some knowledgeable peoples' opinions on this. It doesn't seem to me that most apps are going to these lengths to guarantee security (for example, Facebook Connect seems to assume that you put the secret into a string right in your app).

    Another thing: I don't believe the secret is involved in initially requesting the Access Token, so that could be done without involving our own server. Am I correct?

    • poke
      poke over 14 years
      Sorry if I don't get the obvious, but what is the problem with storing the codes in the application's database? Because those tokens are generated and stored after the user authenticated his account, so it should be safe to assume that said user wants the mobile device to store the access to have access.
    • Felixyz
      Felixyz over 14 years
      Even after the user have authorized you to access their account (on Twitter, say) you have to use a secret that you obtained from the service you're trying to access. This secret is used in all communication with their server, together with the authentication key and some other keys. So yes, you can store the access key, but the secret shouldn't be stored, because it could be used with any authentication key to abuse the service. Again, I would be happy to be corrected by people who know more about this.
    • poke
      poke over 14 years
      OAuth offers an authentication method that secures the original user's login data. To make that possible a new unique login combination is generated that only works together with the unique application's key combination. The big benefit over storing the user's login data is that those are completely safe after first authorization and in any violation case the user can simply revoke the authorization's access. And of course not saving the secret wouldn't make sense as the user would need to reauthenticate then (and that is not what the user wants when giving the application access).
    • Felixyz
      Felixyz over 14 years
      @poke The authentication key that is obtained when the user approves your app with the provider should be saved, but the secret token that you received from the provider before releasing the app should not (in the case of a desktop or mobile app; if it's a web app you can obviously store the key on the server, as stated in the question).
    • Varun
      Varun over 14 years
      As per my understanding of oAuth-- In case of a desktop app its very easy to sniff/monitor the HTTP/HTTPS traffic with tools like this ieinspector.com/httpanalyzer/index.html Hence your token and token secret both can be found very easily. So the only protection is your consumer-secret. Now if your store the secret inside the app and somebody is able to find it, it becomes a child's play to impersonate any other app as your app. Correct me if I am wrong.
    • Matt C
      Matt C almost 8 years
      Similar question here for which I provided this answer stackoverflow.com/a/38582630/752167 TL;DR Web views are naughty
    • Rajat
      Rajat over 5 years
      Have added an answer here stackoverflow.com/questions/46110635/…
  • Felixyz
    Felixyz over 14 years
    As who mentioned? If you mean poke's comment, see my answer that secret != authentication key. The latter can safely be stored, the former can't. I don't know about Android, but gaining root access to an iPhone is not hard at all. Note that the secret is same on all instances of the app, so an attacker would only have to gain access to one binary. And even if they couldn't gain root access on the device, they could get their hands on the binary in some other and pull the secret token out of it.
  • Felixyz
    Felixyz over 14 years
    This is very interesting, although it confirms what I feared, that OAuth is not so great for desktop/mobile apps. Of course, an attacker would have to first get the secret and then also sniff someone's credentials, so it would take quite some determination. The pin solution is ok for desktop but to heavy-handed for mobile imo.
  • Felixyz
    Felixyz over 14 years
    How would your proposed scheme help value-add web services, since this problem doesn't apply to them? Also, I don't see how it would work with the provider generating new secrets, since you would need a "master secret" to even request those new secrets, so you would at least need one call to your own server (which holds the main secret). But that is of course better than routing all traffic through your own server. Clarification most welcome! And please update here as your proposal progresses!
  • kgutteridge
    kgutteridge over 14 years
    just to add it is very easy to root android phones as well
  • Felixyz
    Felixyz over 14 years
    You are right, OAuth was mostly designed with web apps in mind and I'm sure it works well for that. Yes you need the consumer token and secret to sign each request, and the problem is where to store the secret. If someone steals the access key it's not a big deal because it can be revoked, but if someone gets the consumer key every copy of your app has been compromised.
  • Felixyz
    Felixyz over 14 years
    Yes I think this is reasonable. It would take a lot of determination for someone to first extract the consumer secret and then snatch people's credentials to do something mean. For high-profile apps, I'm not sure this would be enough, but for an average app I think you're right that you have to balance implementation time against a pretty minor security threat.
  • davidtbernal
    davidtbernal about 13 years
    Just curious: how do you determine that the thing making a call to your proxy server is legitimate?
  • GrayB
    GrayB almost 13 years
    Good thought, but no. The cracker would just see the binary pointing to the address of the OS constant.
  • Hugo
    Hugo almost 13 years
    wiki.developers.facebook.com is dead.
  • quasistoic
    quasistoic almost 12 years
    All it takes is for one user to exert the effort and then publish or share your secret. Once your secret is out, the risk of your service being shut down completely for abuse skyrockets, and it's completely out of your control.
  • quasistoic
    quasistoic almost 12 years
    In response to notJim: the primary risk in allowing your consumer secret to get out is that malicious (or foolish) applications can be developed using it, tarnishing your reputation and increasing your risk of having your legitimate application shut down for API abuse/misuse. By proxying all calls that require your secret through a web application you control, you're back in a position where you can watch for patterns of abuse and revoke access on the user or access token level before the API you're consuming decides to shut down your entire service.
  • blevlabs
    blevlabs almost 10 years
    Obfuscation is not security at all. This is worse than no security at all, because it gives the developer a false sense of security. en.wikipedia.org/wiki/Security_through_obscurity
  • Mark
    Mark almost 10 years
    I agree with quasistoic here, you will need to use an SSL enabled browser to deal with the oauth call. This is a good thing for a few reasons, including easily managing any security updates in the future, and nothing in the actual application will need to be updated over time. Zac points out Twitter proposing a PIN solution, which I actually thought up as well, because you cannot trust the application to securely obtain the code. I suggest using a 'Nonce' with a modern encryption along with the PIN and secret to proxy the requests through the web server.
  • Cheeso
    Cheeso over 9 years
    Can you elaborate on the "platform specific mechanism to get an app id of some kind"? How is the server component to verify the identity of the client? I think this can be done with client provisioning. For example, deploy a new and unique SSL cert to each client. Is that what you mean? If it is more complex than this, maybe you can refer to a more in-depth writeup?
  • Dick Hardt
    Dick Hardt about 9 years
    I recall some security people talking about how this could be done. There is a call to the OS that returns a signed token that you can then send to your server and verify. Sorry I don't have the specifics. It is an error that could use some good examples.
  • Dick Hardt
    Dick Hardt about 9 years
    OAuth 1 required signing each request. OAuth 2 only requires the access token. Both require the key and secret when acquiring a token.
  • hungryghost
    hungryghost almost 9 years
    "Obfuscation is not security at all. This is worse than no security at all, because it gives the developer a false sense of security." Nonsense. Nobody is saying that obfuscation makes for good security. But if I'm going distribute an OAuth secret with my apk, it's surely better to obfuscate than not. Obfuscation is what Google also recommends when storing keys/secrets in-app. If nothing else, these measures keep casual hackers at bay, which is better than nothing. Blanket statements like yours equates imperfect security with no security. That's simply not true. Imperfect is just imperfect.
  • Rafael Membrives
    Rafael Membrives over 8 years
    @DickHardt but in this scenary how do you ensure that the mobile application is really your app and not a fraudulent one?
  • Damian Yerrick
    Damian Yerrick over 8 years
    Provided the service supports "the client side flow". Many do not, instead requiring the client ID and client secret in order to obtain this access token.
  • C0deH4cker
    C0deH4cker over 7 years
    Obfuscation does NOT help, because no matter how much shifting or encoding you do, you still construct the key together and use that to build your API request. It is fairly simple to dynamically hook APIs in the right places to dump out the request you're sending before even HTTPS encryption. So please, don't embed secret keys in your app unless there really is no possible alternative.
  • Hudi Ilfeld
    Hudi Ilfeld about 5 years
    doesn't this make the life of the hacker easier?! because now, in order to access the server resources we technically jus need the client id, since the server will anyway append the secret to the request. am I missing something?
  • Gudradain
    Gudradain about 5 years
    @HudiIlfeld Yes you are missing something: the client needs to login to the server. As long as he is not login, the server won't return anything. One way to manage this is after sending the credential for the first time, the server return an access token to the client and then the client send this access token with every future request. There are many options here.
  • Ivo Pereira
    Ivo Pereira over 3 years
    @Gudradain I am not sure how your solution helps here, as all of that can be automated: 1) Client sending client_id to server. 2) Server returning an Access Token for Client to send it in next requests? Why exactly? But let's assume it is okay. 3) An hacker now is authenticated against the server, and is still able to make any API/service requests he wants, still being impersonated behind your proxy server. Am I missing something here?
  • Ivo Pereira
    Ivo Pereira over 3 years
    Beware that this can still lead to Client Impersonation: tools.ietf.org/html/rfc6749#section-10.2
  • Gudradain
    Gudradain over 3 years
    @IvoPereira Putting the client secret in the application make it easy to steal it. Once someone has your client id and client secret, they can impersonate the client. Varying amount of damage can be done if someone impersonate the client depending on the app. If you want more information, I would suggest that you ask another question (not a comment).
  • Ivo Pereira
    Ivo Pereira over 3 years
    @Gudradain I wasn't suggesting that exact flow either for the reasons you mentioned, however just using a Proxy in the middle wouldn't solve the issue for itself as it would open another free door to a bad actor. However this might help mitigate the issue: medium.com/@benjamin.botto/… (Enhanced Architecture -> Security Considerations)