How can one prevent clients from sharing OAuth tokens

2,309 views
Skip to first unread message

Vishal Bhasin

unread,
Dec 1, 2012, 5:09:04 PM12/1/12
to api-...@googlegroups.com
Hello All,

I'm looking for ideas to prevent customers from sharing oauth tokens, i.e. the customer that created the token should only be the one using it. What can one do on the server side to prevent this customer from sharing the token with someone else?

Thanks and appreciate your responses/ideas,

Vishal

Jeff Schmidt

unread,
Dec 2, 2012, 11:57:22 AM12/2/12
to api-...@googlegroups.com
Hi Vishal:

For the application I'm working on, we don't have end user data and user specific OAuth tokens, but we do have tenant specific tokens.  A tenant application uses its issued client credentials to obtain bearer tokens, and then hands them out to the user agents accessing their site.   This token is then used by the user agent to make cross-domain (JSOP) API calls directly to our server. By issuing that token, the tenant has authorized the user agent to access our APIs, as well as any tenant specific content used to satisfy the requests.

Being a bearer token, the bearer gets access. Token acquisition and the API calls themselves are performed over HTTPS, so an eavesdropper can't just pull tokens out of thin air, but on the client side, a user can inspect the DOM, or a non-browser client can gain access to the token and send it off elsewhere.

In our case, the server keeps additional token specific information.  My app is Java based, and I use Spring Security OAuth. However, that framework does not provide anti-hijacking, usage limits etc.  So, once Spring Security has okay'd the token and my RESTful APIs process the request, I have an additional chain of request processing that goes on before any API request is satisfied.

After a tenant app has obtained a token and handed it to a user agent, I only know a given token was created and that gets persisted. The very first API call in which that token is used is what I call the 'token binding event'.  That is, the client source IP address is associated with the token. Then, for the lifetime of the token, if it is used by any other source IP address, the token is considered hijacked and is made invalid.

That may or may not be iron clad enough for you. As you can see, there is a window before binding where the original recipient of the token could hand it off to any other client.  But, once that binding occurs, a particular IP address is locked in.

Originally, I thought having the tenant application supply the client IP address at the time the token is acquired could close that window. But, many companies, institutions etc. can access their tenant application using private IP addresses. Then the source address seen by the tenant app, and that seen by my server would differ.  Also, using Network Address Translation (NAT), many individual clients within a private IP space will share a single public IP address. So, my token hijacking mechanism cannot distinguish at that level.

Anyway, that's what I have, worts and all.  I'm very much interested in what others suggest in how to improve on this or do it differently.

Moving beyond that, I'm also interested in other asset protection ideas.  I'm not talking end user data here, but rather the large corpus of valuable, curated data our application serves up via its APIs. Allowing a client to systematically pull content is not in our best interest.  So, for an individual token, I've implemented:

(1) A given token is only good for so many API points. Once reached, the token is invalidated.
(2) Since we control both sides of the conversation for the most part (embeddable widgets on the client, control server), if token usage appears excessive over some interval of time, the API can return that a captcha challenge must be satisfied. The objective is to stop, or slowdown some program that acquired a token and is scraping content.
(3) If the captcha is unsatisfied for x number of API calls, then the token is invalidated.
(4) Even if captcha is satisfied, but the number of challenges is excessive, the token is invalidated.
(5) The token itself expires in 24 hours.

That all seems well and good, but if tokens are easy to get (tenant application), then once the current token is invalid, simply get another one and keep going. To this end we go back to the token binding event I described earlier.  If a given source IP address binds too many tokens within some period of time, it gets blacklisted for a period of time. The server will not honor any token presented by that client while blacklisted.  A repeat offense can result in permanent (administrative) blacklisting.  There is a whilelisting mechanism as well.

As you can guess, the blacklisting mechanism itself has its problems.  Going back to NAT, if there are 1000s of clients sharing a single public IP address legitimately going about their business, that could look like abuse. That address can be whitelisted, but that disables the ability to blacklist.  I'm not happy with this solution; things are not fine grained enough.

Other suggestions would be greatly appreciated.

Cheers,

Jeff

Bill Wilder

unread,
Dec 2, 2012, 3:01:53 PM12/2/12
to api-...@googlegroups.com
Hi Jeff:

Re: "The very first API call in which that token is used is what I call the 'token binding event'.  That is, the client source IP address is associated with the token. Then, for the lifetime of the token, if it is used by any other source IP address, the token is considered hijacked and is made invalid."

Do you support mobile clients? Seems these can change source ip address from one call to the next. Or is invalidating & reissuing tokens sufficient in practice?

Cheers,
-Bill
--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group, send email to api-craft+...@googlegroups.com.
Visit this group at http://groups.google.com/group/api-craft?hl=en.
 
 

Jeff Schmidt

unread,
Dec 3, 2012, 1:17:20 PM12/3/12
to api-...@googlegroups.com
Hi David:

Our existing few tenants are browser based.  There is not yet a direct mobile app invoking the APIs.  I do fully expect to have to make changes here and there to accommodate new situations.  That's another good reason to solicit more ideas on how to handle the situation, beyond the echo chamber of my own head. :):)

I run afoul of the current implementation myself.  Sometimes during development and testing on my local system, for whatever reason I see the source address as the IPV4 loopback address, and other times IPV6.  Likewise, with a session in progress with a tenant application, connecting to the company VPN and then continuing to use the tenant app results in a hijacking since my address changed.

Likewise, the person using the application at work and then taking their laptop home, or uses cellular etc., the token is hijacked etc.  And, as you said, if a mobile device is receiving new public IP address assignments, hijacked.

So, I was trying to address this at a higher level. We've instituted a token renewal mechanism.  This is not an OAuth refresh token, but rather the client just presenting a new token obtained from the tenant application.  In our browser based world, JSONP is limited to HTTP GETs, and the callback function is invoked only with status 200 (OK).  So, errors, whether client or server, or token related, are communicated within the returned JSON.

Given the provided widget layer, when an indication that the provided token is invalid (for whatever reason), there is a local JavaScript event issued that can be handled by the tenant.  By default, handling just displays a message that the token is invalid and that you should restart your session etc.  Not very smooth, but a tenant can provide their own functionality, and acquire another token, and then the widgets will just go with it. The user should not know that happened, other than perhaps a slight delay in acquiring the new token.

Anyway, was the token hijacking malicious?  How to know?  The hijacker has gone and obtained a new token (with the tenant's assistance), and the hijackee will also have to get a new token.  Of course, if this is the same device then it has moved on and won't care about the prior token.

Other scenarios are handled similarly.  I talked about the captcha and API usage limits per token etc. Just like hijacking, token renewal is used to get a new token.  But in the grand scheme of things, how do you protect your content?  I think I have some measures to help deter the casual abuser, but with enough source IP addresses (bot net, say) the content could be had...

I wish I had better solutions.

Cheers,

Jeff

Jeff Schmidt

unread,
Dec 3, 2012, 1:20:04 PM12/3/12
to api-...@googlegroups.com
That's what I get for writing email to David right before addressing this thread...  Sorry Bill! :)  I did not see a way to edit the post...

Jeff

Felipe S.

unread,
Dec 4, 2012, 6:22:59 PM12/4/12
to api-...@googlegroups.com
Hi Guys,

Isn't the OAuth2 implicit grant designed for the browser application use-case?

We are currently working on implementing it within our infrastructure hence I am pretty sure that the Bearer-Grant is not really meant for Browser-Server communication but for Server-Server communication.
We use it for communication between systems within our company boundaries where we have a certain level of trust.

Obviously you have the "issue" of the reosurce owner having a) to be authenticated and b) having to confirm the access.

Can you give a little insight why decided not go with the implicit flow?

Cheers,
Felipe

Jeff Schmidt

unread,
Dec 5, 2012, 3:32:58 PM12/5/12
to api-...@googlegroups.com
Hi Felipe:

In my particular scenario, I don't deal with end users and their data, and the resource owner is in effect the tenant application (and us, by providing a large corpus of shared content). The user agent is not redirected, and the user does not authenticate.  Basically, the tenant application uses their client credentials to acquire a bearer token; server to server over HTTPS to keep the credentials secure.  The token is is then handed over to the user agent, and it is definitely exposed in the DOM. But, no credentials are exposed.

How the tenant application decides to provide a token (e.g. user must login on their end, anonymous user establishing an HTTP session) is not our concern; but by handing this token to a user agent, the tenant is authorizing access to their data (and ours) via our APIs. They are also accepting responsibility for charges incurred if there is a API call cost etc. Still working on those monetization mechanisms. :)  That's it.  Perhaps this is an unusual scenario, since we all typically encounter OAuth ourselves when authorizing an app to access our data elsewhere.

Anyway, for me, that's the easy part. Trying to deal with abusive use of a token is another matter.

Cheers,

Jeff
Reply all
Reply to author
Forward
0 new messages