Before I get started, let me say that this should be taken with a very large grain of salt. I am not a technical expert in these areas. I've only done a fair amount of reading and following along with standards efforts. Conclusions here should be questioned thoroughly and corrected as necessary, but since no one else seems to be willing to systematically look into the performance argument for signatures over SSL/TLS, I thought I'd just sit down for a couple of hours and pound it out. The following is the result of that work.
The crux of the trade-off comes down to this: In the case of signed authorization information (with a nonce), a Man in the Middle (MITM) attacker owns the individual message. The MITM can do the following:
In the case of bearer-token authorization, a MITM owns the entire connection. The MITM can do the following:
In my opinion, #5 makes bearer-tokens without SSL/TLS unusable in nearly all use cases. Any use case where spam is a threat, for example, is not an acceptable use case because of this attack because any MITM can send an arbitrary number of spam messages that the provider application will show as coming directly from the user. If you think Twitter direct-message spam is bad now...
Because of this and other possible attacks (successfully impersonating a provider gets you the bearer-token, for example), I think that bearer-tokens without SSL/TLS are not worth considering further for the vast majority of use cases.
Yes, but there are tradeoffs.
The most important and unavoidable tradeoff is performance. The performance tradeoff comes in two flavors:
Connection latency is incurred to the public-key cryptography operations that are used to facilitate the exchange of a shared secret, which can then be used in the much more efficient private/symmetric key cryptography used to encrypt the individual messages. Research (1 - pdf) indicates that, on the web server, SSL introduces approximately a 70% overhead over basic HTTP for small requests and that of this overhead almost 90% is incurred in the public key operations.
As request size increases, the public key operation overhead remains constant while the private key operations to encrypt the request scales more or less linearly with request size. As a result, the actual act of encrypting the request becomes the limiting factor relatively quickly for large requests.
Keep in mind, this is additional latency on the web server, not on the client. Other research (2 - pdf) indicates that clients may be even more resource-bound for these types of operations, resulting in even more severe latency problems.
It's important to note that these two types of performance impact become problematic under different use cases.
SSL has negative performance impacts which will result in real user experience performance impacts in certain situations. Service providers can use specialized hardware to significantly accelerate the necessary cryptography operations, but any client smaller than a medium-sized web application provider will not be able to afford the cost of such hardware. As such, these clients will suffer a user experience impact from the required use of SSL/TLS connections in some situations.
What are these situations?
Connection latency is an issue when new connections must be established for most operations. This is the case for intermittent API requests. Some use cases where this could be an issue (keeping in mind that even an extra fraction of a second of wait-time is a user-experience penalty that many applications may be unhappy paying):
Meanwhile, encryption of the request becomes an issue for large request uploads and download especially. Some examples:
In both of the situations outlined above, SSL/TLS imposes a performance overhead that should theoretically have user experience implications. As I've been thinking about this issue, the following matrix has proven helpful in visualizing the problem space and helping to show that SSL/TLS is a clear winner in only a limited (but admittedly very common) portion of the problem space.
| Sensitive to connection latency | Not sensitive to connection latency | |
|---|---|---|
| Large requests | SSL/TLS not a good option | SSL/TLS may be an option |
| No large requests | SSL/TLS may be an option | SSL/TLS is a good option |
The answer to this question depends on the form that signing ends up taking. If only the authentication parameters are signed, then we are in a situation similar to OAuth 1.0a in which latency is minimal because the hash operation used in the signing is cheap and is executed on a very small amount of data. Further, performance is unrelated to request size because only the authentication parameters are signed and the length of these parameters are unrelated to the request payload.
If full message signing is required, then we start to run into the encryption penalty, as effort to calculate the hash of the entire payload should scale more or less linearly with the size of the payload. However, connection latency should remain minimal for small requests.
Of course, using signatures without transport-layer security brings with it a whole new matrix of known security considerations. As mentioned at the beginning of this little essay, from a security perspective, signing appears to be at least as good in all respects as bearer tokens sent in the clear.
There are theoretical and currently deployed use-cases in which dispensing with SSL/TLS and signing at least the authentication parameters of a request makes sense. These are use cases in which SSL/TLS has an undesirable user experience impact and in which leaving the request payload in the clear does not have significant negative security impacts. For this reason, and because the signing approach is the predominant deployed OAuth method (even though SSL/TLS with a bearer token is an option), we should maintain a signature method in the current draft.
There is an ongoing meme that OAuth provides little or no security benefit in client applications. I believe that this assertion is incorrect.
Client applications are applications that run on my computer or phone and so are implicitly "trusted" by me. (I use quotes because I think that the assumption of user trust for client applications is wrong, but that is neither here nor there.)
I already addressed this somewhat obliquely in my OAuth FAQ Part 1 and Part 2, but it bears repeating, which I just did on the OAuth Google Group here.
To quote myself:
One major security benefit of using OAuth for client apps is that the client is only provided with an access token for the service and not the user's password.
If the access token and consumer secret are compromised, then either can be revoked, either by the user (in the case of the access token) or by the provider (in the case of the consumer secret). In most provider implementations a request authorized with an access token is not allowed to update certain aspects of the user's account, such as the password.
If the client requires the user to input their password (for example, Google's ClientLogin protocol) and the client becomes compromised, then the password is exposed, allowing full access to the user's account. Game over.
In my mind, this is *the* reason I want clients I use to use OAuth rather than a username/password login scheme.
I would be happy with another token-based login scheme as well, but OAuth is a perfectly good, publicly reviewed standard and I see no reason why a provider should cook up a bespoke token-based authorization scheme when OAuth is available and works for clients.
In other words, developers should use OAuth in their phone and desktop applications and users should demand it. I do.
This the continuation of my ongoing OAuth Q&A, now with fewer links and more editorial commentary. See Part 1 as well.
If I have access to an authorized token and the consumer key and secret, I can make "authorized" API requests galore. So OAuth is no more secure than the username/password pattern.
That's not a question. Way to start off part 2 with a big fail!
[Ed. - Ahem . . . You're asking the questions as well as answering them.]
[Me - I deny that. But okay, let's try again at a real answer.]
This is only partly correct.
First, OAuth provides the a pattern for providers to scope access much more granularly than when a single username/password pair gives total access to an app. For example, most OAuth providers do not allow access to administrative functions when authorizing with an OAuth token, so a rogue client cannot change a user's password. Because of this, the user's access to the app can be guaranteed and damage can be limited to the scope of access granted to the client.
Second, because the user's access can be guaranteed and because client access can be managed at the level of the token, authorization for a given token can be revoked in a self-service manner. The scenario here is that a user grants access to a malicious app that vandalizes the account. The user realizes this, logs in to the provider, revokes the consumer's access, and repairs (hopefully) the damage. Because the malicious consumer cannot change the password on the account, the provider does not have to become involved in the initial response to the vandalism. Follow-on activities that the provider may need to become involved in (like account restoration or consumer key revocation) still exist, but the need for instantaneous response is lowered.
Hey, you just said "consumer key revocation", but back in Part 1 you said that the provider can't assume a consumer key uniquely identifies a particular class of consumers. What gives?
It is correct that the provider can't make this assumption based on the OAuth specification. However, the provider can impose requirements around the consumer key on consumer developers, and the provider can reserve the right to revoke a consumer key for whatever reason they choose. This could be required in the case of denial of service attacks or malicious consumers using a particular key. Providers should work closely with consumer developers to clearly lay out what actions the provider will take in these cases and what options consumer developers have.
Providers should recognize that the case of desktop and web apps are significantly different in the case of key revocation and they should plan accordingly. In the case of web apps, it should be relatively easy to replace a compromised consumer key and secret. In the case of desktop apps, the consumer developer may face the task of updating thousands or millions of installed applications in the case of a key revocation.
Let's assume that a user has installed a malicious desktop app that wants to use the API of my web app. What's the point of requiring OAuth, since this malicious desktop app already owns the user's system and will have access to anything the user types?
I'm not sure where this assumption comes from. Well, let me amend that. I know exactly where this assumption comes from, but it is still incorrect. Let me assure the reader that there are many platforms where the installation of a malicious application does not translate into ownership of the host system. The reader will find this sort of behavior in any properly configured Unix-like operating system including Linux, on the iPhone, in any modern browser, in Mac OS X, and even in some locked down versions of the Windows operating system.
On these platforms, even if the user is tricked into installing a malicious client or going to a malicious website, the user may still be careful to verify that they are only entering their password into the real site of the provider. There are a lot of options for verifying this, but the best way is for the user to make sure that he or she always enters there password into their provider's site using a modern browser with anti-phishing technology and using an https connection.
I've been seeing a lot of misinformation about OAuth in discussions lately. Mostly, this is because there has been a lot of activity around OAuth due to the announcement that the Twitter API will be supporting OAuth and eventually (probably, and less officially) moving to OAuth-only authentication and dropping support for basic auth entirely. Generally this misinformation is rebutted somewhere else on the web but it can be somewhat inconvenient to track down all of the call-and-response blog postings on the topic.
As such, I thought an O'Grady-style Q&A might be in order, based on my notes and recollections. Said Q&A turned out to be a little longer than expected, so I'm doing it in a number of parts that will be determined by the cessation of misinformation or the end of my attention span, whichever comes first. If there are any inaccuracies included in these posts that I become aware of (On the web? About OAuth? From a non-expert? Impossible!), I'll post corrections inline.
What was OAuth designed to do?
OAuth was designed to do delegated authorization, which is a fancy way of saying that it was designed to ensure that a user will never have to give the password for a service to any entity other than the service provider. If the user wishes to use an application that is not the provider itself in order to access the provider (for example, using Twhirl to access Twitter, or Plaxo to access your Google contacts), then that application can use OAuth to request authorization, which is then granted in a transaction that occurs directly between the user and the provider and does not involve giving the password to the application.
You can read lots about it on the OAuth site, the OAuth wiki, the OAuth mailing list, on Eran Hammer-Lahav's site, and the Google identity and authorization site.
OAuth doesn't work in desktop applications because there is no way to protect the consumer key or secret, so there's no point in using it here, right?
No, OAuth does what it was designed to do just fine in desktop apps.
But doesn't OAuth rely on a consumer secret and key to identify applications that are allowed to access protected resources and services? How do I protect that in a desktop application?
OAuth neither requires nor assumes that the consumer key and secret are hidden from other apps (though there are some nice payoffs if you can manage this). The consumer secret is simply not sent over the wire. Providers should not assume that consumer keys or secrets identify specific consumers or classes of consumers. Note that this may require providers to treat desktop consumers differently than web apps where requests come from a single IP address and the consumer has more control over the key than is the case with desktop apps.
My company has a web app and we also provide a desktop client. Because we provide the client, we can just use username/password authentication in the client and that's safe, right?
No, and there are two reasons for this. First, doing this teaches your users that responding to the password anti-pattern is acceptable behavior and makes your users more susceptible to malicious API clients that ask for their password. Second, this client behavior necessarily results in the user's password being stored by the client in a recoverable format, which is a significant security risk.
OAuth is really just a standard for token negotiation and request signing. My application already generates API access tokens and I have a scheme for sending the token along with the request, so why do I need OAuth?
The most important reason is that there are a lot of things that can go wrong with API access tokens, especially when used over an insecure transport (http instead of https). Using a public, peer-reviewed standard lets you rest easy knowing that lots of experienced thought has gone into avoiding security issues.
Well, okay, but I've actually got the best security minds in the business working on my access token scheme, so I'm pretty comfortable there. What are the other reasons?
The next biggest reason is interoperability. There are lots of OAuth [client libraries] that make it relatively easy to inter-operate with systems that use OAuth as their auth delegation protocol. For example, Shindig (OpenSocial, Google Gadgets, iGoogle, etc.) has built in support for OAuth API access for gadgets running on the platform. I expect that within a year there will be at least one web "glue" application (like Yahoo! Pipes, or Tarpipe) that will support reads from and writes to arbitrary OAuth endpoints. If you use a custom scheme, you will miss out on this interoperability.
For the second post in my pluggability series (series? seriously?), I'll return to the issue of trust, specifically what I was talking about when I said
Trust (between systems) in the enterprise has been all or nothing. With the emergence of SaaS and the integration of consumer services, this approach doesn't work anymore. Access delegation capabilities are becoming essential. OAuth is part of the answer to this issue. Standards, architectures, and UIs that can handle multiple delegation are probably the end-state solution.
Let's take this apart a bit, with the caveat that I just fiddle with security schemes and my real current interest is in the data user interface area, roughly.
There are several different types of trust between systems and I'm not going to capture them all in the discussion below, but the basic types are trusted systems (where we ask the question, "Do I, system X, trust the integrity of system Y?"), identity verification and authentication ("Do I trust that this user/system is who it says it is?"), and authorization ("Given that this user/system is identified, what access do I trust it with?").
This is all relatively straightforward in the classic situation of a user trying to log onto a system. Yes, the user is trusted. Identity is verified via a username/password pair and we protect against man-in-the-middle attacks using a VPN. Authorization is provided for on a user-by-user basis.
It's also straightforward in the circumstance where a server is attempting to communication with another server. Again, integrity is assumed because the server is known, authentication is carried out under one of a number of schemes, and authorization is on a per-system basis.
But when we're now in a world of agent systems acting on behalf of users, and these systems start to fall apart. How do I treat a system that claims it is acting on behalf of a user? Do we grant authorization appropriate to the user, or just punt on the question and let the trusted system figure it out? How can we be sure that the system is acting on behalf of the user that it says it is acting on behalf of. What if the system requesting access is one we've never heard of before? Do we trust it?
This is the problem of access delegation. (To be clear, this is not the related problem of single-sign-on.) There are a couple of general approaches to access delegation in the enterprise, neither of which access delegation:
So what would have to happen to allow for user-driven pluggability?
First, authorization schemes that allow for layered access controls by user and system. In some organizations, access from anonymous systems and applications on behalf of users would be allowed, and this access would be granted at a default minimal level (display only, no access to sensitive data, etc.).
Second, in all organizations a path to request and receive certification of a given application at a particular access level should be provided for. I don't have high hopes for this in a world where a large number of companies still block GMail at their corporate firewalls, but a boy can dream.
Third, standards for access delegation must become available so as to allow for automatic interoperability of delegated access systems. We still may need an open loop in an enterprise environment, as in step 2, but it shouldn't be technically required. OAuth is probably the best bet here, as all enterprise schemes appear to be pretty much vendor-specific. Hopefully the IETF push will start to propel OAuth into some enterprise vendor's products, though I'm not holding my breath.
Fourth, working out the user interface is an ongoing major issue. Single delegation is hard enough right now, but my impression is that the OAuth community is getting pretty close to nailing it down. Multiple delegation is going to be a real headache, but people are starting to think about it, and there's no question in my mind that it's where we need to get for pluggability to be really workable while maintaining (Question: why do I bother writing this stuff when someone at Google has already done it?)
This all begs for a bit of an example. Google's example (link) is a good combined consumer-web/enterprise thought experiment, but it's a target for a few years out, certainly. More simple examples done well (reporting systems signing onto data-warehousing or operational systems, for example) are hard enough to come by in the enterprise as is. Hopefully that'll be content for another post.