views:

1322

answers:

7

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 you 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. I don't believe using https is any help.

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, where a script would append the secret to the request data and communicates 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?

+4  A: 

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: http://apiwiki.twitter.com/Authentication https://www.yammer.com/api_oauth_security_addendum.html

Zac Bowling
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
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!
Felixyz
A: 

As others have mentioned, there should be no real issue with storing the secret locally on the device.

On top of that, you can always rely on the UNIX-based security model of Android: only your application can access what you write to the file system. Just write the info to your app's default SharedPreferences object.

In order to obtain the secret, one would have to obtain root access to the Android phone.

Christopher
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
just to add it is very easy to root android phones as well
kgutteridge
A: 

I don't have a ton of experience with OAuth - but doesn't every request require not only the user's access token, but an application consumer key and secret as well? So, even if somebody steals a mobile device and tries to pull data off of it, they would need an application key and secret as well to be able to actually do anything.

I always thought the intention behind OAuth was so that every Tom, Dick, and Harry that had a mashup didn't have to store your Twitter credentials in the clear. I think it solves that problem pretty well despite it's limitations. Also, it wasn't really designed with the iPhone in mind.

bpapa
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
+2  A: 

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.

Jayesh
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.
Felixyz
+1  A: 

Here's something to think about. Google offers two methods of OAuth... for web apps, where you register the domain and generate a unique key, and for installed apps where you use the key "anonymous".

Maybe I glossed over something in the reading, but it seems that sharing your webapp's unique key with an installed app is probably more secure than using "anonymous" in the official installed apps method.

Greg Bulmash
A: 

Facebook doesn't implement OAuth strictly speaking (yet), but they have implemented a way for you not to embed your secret in your iPhone app: http://wiki.developers.facebook.com/index.php/Session_Proxy

As for OAuth, yeah, the more I think about it, we are a bit stuffed. Maybe this will fix it.

oliland
A: 

I agree with Felixyz. OAuth whilst better than Basic Auth, still has a long way to go to be a good solution for mobile apps. I've been playing with using OAuth to authenticate a mobile phone app to a Google App Engine app. The fact that you can't reliably manage the consumer secret on the mobile device means that the default is to use the 'anonymous' access.

The Google App Engine OAuth implementation's browser authorization step takes you to a page where it contains text like: "The site <some-site> is requesting access to your Google Account for the product(s) listed below"

YourApp(yourapp.appspot.com) - not affiliated with Google

etc

It takes <some-site> from the domain/host name used in the callback url that you supply which can be anything on the Android if you use a custom scheme to intercept the callback. So if you use 'anonymous' access or your consumer secret is compromised, then anyone could write a consumer that fools the user into giving access to your gae app.

The Google OAuth authorization page also does contain lots of warnings which have 3 levels of severity depending on whether you're using 'anonymous', consumer secret, or public keys.

Pretty scary stuff for the average user who isn't technically savvy. I don't expect to have a high signup completion percentage with that kind of stuff in the way.

This blog post clarifies how consumer secret's don't really work with installed apps. http://hueniverse.com/2009/02/should-twitter-discontinue-their-basic-auth-api/

Martin Bayly