I have an API that will be used on mobile apps. I want to secure it, potentially using OAuth, but there seem to be some pretty obvious flaws with how it works.
Based on other apps that I've seen, it looks like a common approach is to pop up a web browser view inside the app (this would be a UIWebView in iOS for example) for the user to enter their service credentials. The problem I see with this is that, at least in iOS, the app developer has full access to the information typed in by the user on the web form. So when you use clicks "Submit" on my service login page, the app developer can easily get their clear text username and password. Doesn't that pretty well defeat the purpose of OAuth?
And even if you don't use the embedded web browser, but instead you close the app have the full web browser app (i.e. Safari) pop up, the app developer could easily take them to their own spoofed up login page that looks like my login page, but is actually just stealing their username and password.
So am I misunderstanding something? At this point I can't see why I would bother using OAuth when it's so easily circumvented by nefarious developers.
EMPLOYEE0Oauth mandates every call to happen over ssl. So that will make a man in the middle attack quite difficult .
What you need to think about is :: The end user when is authenticated is that happening against your user store ? Then you need two legged Oauth . But if you just want to authenticate the app then you need a 2 legged oauth flow in which case there will be no pop up login page.
Ideally there will be a method called /authorize . When this endpoint is invoked it should be called with client id and secret . Once this call comes in the backend validates the client id and secret and then does a 302 redirect to the login page. And the whole thing is happening over ssl.
If you still feel this is insecure you might want to take a look at mac token based flows of OAuth http://tools.ietf.org/html/draft-hamm....
EMPLOYEE2If you are working on an API that will be used by third party developers, then there is no magic bullet that will prevent developers from using your API in bad ways. However I think that OAuth 2.0 helps you reduce the risk.
In fact, I would argue that if you have a web page that lets people log in to your service using a username and password, then the risks that you describe -- chiefly, the possibility that a nefarious developer will put up a fake "login page" for your service -- are present whether you have an API or not and whether you use OAuth or not.
Rather, I think that there are some risks that OAuth helps you minimize.
For instance, if you simply set up your API using HTTP Basic security, or if you use OAuth 2.0 with the "username / password" grant type, which allows a developer to send a username and password to your API in one call, and get back a token -- then the developer, in all cases, has access to the clear text password without any special hacking. Sure, the developer could be evil and do something bad with it, but more likely the developer will make a mistake or not think and write the password in cleartext to her own database, or leave it sitting around on the device unencrypted after the app is uninstalled, or print it out in a debug log that gets stored in the cloud and indexed by Google, and on and on.
On the other hand, the "authorization code" grant type in OAuth 2.0 requires that you open a web browser window that directs the user to a special authentication page, and the password is entered directly on that form. I am not enough of an iOS developer to know how as a client-side developer you can access those cleartext forms rendered by another site from inside an iOS app, but if you can then that's too bad. I still imagine that an attack like that requires more work than accidentally writing the cleartext password to a log, however.
Either way, once the user is authenticated, then on the mobile device you can store the OAuth token locally, and not the pasword. The OAuth token is random, long, has a limited lifetime, and can be revoked without affecting the underlying user credentials. So, it's safer to store the token on the device between app launches than the original password, which also reduces risk.
Finally, I'll say that regardless of how you do authentication, this shows you the importance of assigning each app a unique set of credentials, which is a fundamental part of both OAuth 1.0 and 2.0.
For instance, imagine that a developer DOES use your open, public API to forge a login page and harvest user credentials. If you have some good logging and analytics on your API, or user feedback, chances are you'll find out eventually, in which case you can immediately revoke the app's credentials.
Or, if your API is only open to your own developers, then OAuth requires that an app include its own credentials before making any token requests. It's a lot harder for an evil developer to build an app that spoofs your authentication protocol if they can't get credentials to ask for an OAuth token in the first place.
Like everything in security, it's a matter of reducing risk because you can never totally eliminate it, and I think that OAuth 2.0 helps a lot in this area.
And what is the alternative? If you use plain HTTP Basic authentication then the app developer still has access to the cleartext password, and unless you combine it with a separate set of application credentials, you can't disable access to a separate app. If you design some other mechanism that:
1) Validates app credentials
2) Validates username and password
3) Returns a "token"
Then you end up with your own version of OAuth.
EMPLOYEE2To add to Greg's excellent post, it is also worth noting that [edited]:
- Credential negotiation with all apps eventually comes down to trust. The moment an application goes rogue, a provider can invalidate all of the authorizations that had been granted to that app. (Greg touched on this.)
- That provider could also force a password reset for all users of the rogue app, since they know which users had previously granted authorization.
- If the native browser flow is triggered, the best-case is that the end user is already logged in to the service so that no password has to be entered. (embedded browsers usually get in the way here)
- OAuth 2 gives the app the ability to ask only for scopes it needs and to increase them later, if necessary. That way devs can ask for what they need when they need it.
Thanks for the helpful replies. I think we are basically in agreement about things.
The fact is that iOS makes it very easy to access the form data of an in-app browser, so getting access to the user's credentials does not require any hacking. You simply have to overload an event handler and inspect the object that gets passed in. It's a "feature" of the system. I'm not sure about Android but I wouldn't be surprised if there was a similar issue.
The other option would be not to use the embedded web browser, but to close the app, launch Safari, and go to the service login page from there. I *believe* if you do it that way the app cannot directly access the web form. Of course, then the user must copy or write down a special code, close Safari, re-open the app, and enter the code. Far from a pleasant user experience. That's not an option for us. Plus the whole spoofing thing mentioned earlier.
I agree with all your points about storing tokens instead of credentials, the ability to disable misused tokens and/or applications, etc. But at the end of the day, the app developer can still do nasty things if they want. If you have the luxury of hand choosing your partners, then that might be fine, but it's a moot point when open your API up to any developer that wants to make apps for it (as we would like to do). Then all you can really do is try to mitigate damage once it's done, assuming you discover it.
I'm considering writing a UI widget for developers to use that abstracts away all the sensitive data. It would probably be some kind of dialog that lets the user enter their username and password, make the API calls, and returns an access token. At least then the developer wouldn't be directly handling user credentials. Of course, whether or not they use it would be optional so it's not a perfect solution.
I'm not saying that OAuth shouldn't be used or that there are better alternatives, but simply that it's pretty easy to subvert, at least the three-legged login piece. I know that no security is perfect, but it seems like OAuth doesn't handle the mobile app domain very well.
And just FYI, we are not going to use OAuth 2 because the spec is still too instable at this point.
EMPLOYEE0I do agree that it seems too easy for the malicious developer to abuse users... However, the act of installing an app from the appstore is already a permission-granting negotiation that is fraught with peril. In some ways, the cat is out of the bag before the API consents have been granted.
If you used the native browser, couldn't you register a URL scheme to handle the returned tokens at the end of the dance?
OAuth 2 is a final spec. What is it about the spec that seems unstable to you? What are you thinking of implementing instead? What about implementing 2-factor security?
Hey Marsh, you could do some kind of redirect where the URL contains the tokens but there's no automated way to communicate that from the Safari app to the developer's app (as far as I know). I believe the user will have to cut and paste the code or write it down and type it in.
Looks like you're right about the state of the OAuth 2 spec. Everything I was reading seemed to indicate that it wasn't ready yet. Nonetheless, I won't be using it. The industry seems to think it's not particularly good (lots of people resigning from the project). And even though it's finalized I'd like to see how well it stands up to real use before I implement it in case we end up a repeat of the OAuth 1 and 1a situation.
I am currently looking into other options. Not sure what I'll be doing at this point.
I have similar concerns. As an enterprise app developer, I would rather not have the potential to capture a user's password. Ditto as a service developer. In fact, I would rather the user didn't have to "log in" when using my app at all.
I'm coming from an environment where all the clients were running Windows, all the browsers were IE, all the servers were Windows, and everything was on the same Active Directory domain. Authentication was something that magically happened with a little bit of configuration.
Now I'm getting introduced to PhoneGap for our enterprise apps, and feel like I'm back to square one where authentication is concerned. It seems like I ought to be able to accomplish fairly transparent authentication using ADFS, or user certificates on the device, or some combination of those. But I haven't yet connected the dots.