64

Apologies if this has already been asked and answered; I've looked around a bunch but haven't found exactly what I'm asking.

--

  1. Suppose my web app at http://example.com/ uses a private and undocumented web API at http://api.example.com/ to fetch data, e.g. via XHR or JSONP.

  2. Also suppose that this web app is anonymous — it does not require user login.

  3. Since there's communication between client and server, anyone can open Fiddler, etc. to see the exact request and response, not to mention inspect the client-side JS code.

In a case like this, how can you prevent someone from using your API in a non-web client app? E.g. an iPhone app, or server-side.

To my understanding, point #2 removes the option of something like OAuth, and point #3 removes the option of e.g. API keys or even SSL.

I've thought about things like time-based tokens or secret salts that are injected into the page on first load, but an iPhone app could easily just secretly load your webpage before making API requests.

So is there any way besides just plain obfuscation — security through obscurity?

--

In case all that is too abstract, here's a simple example:

Google.com fetches its auto-complete data via some API that's private and undocumented — but open on the web. What's to stop me from using it in my iPhone app?

jww
  • 97,681
  • 90
  • 411
  • 885
Aseem Kishore
  • 10,404
  • 10
  • 51
  • 56
  • 11
    Google's Terms and Conditions and the fact they have more money and lawyers than you? :P – alex Mar 17 '11 at 00:19
  • 2
    How would they know though? I'm genuinely asking; it's trivial to spoof User-Agent and Referer, every user has a different IP address, etc. – Aseem Kishore Mar 17 '11 at 00:25
  • @Aseem They may not necessarily know, but they are probably serving millions of legitimate requests a minute, whats a few outside requests? – alex Mar 17 '11 at 00:30
  • 1
    What do you mean how would they know? Don't they know everything? I mean, we're talking about Google here. – Zed Mar 17 '11 at 00:33
  • 1
    @Alex So what you're saying is, it's not an issue for Google. What if yo're not as big as Google? – Aseem Kishore Mar 17 '11 at 00:49
  • @Aseem An XHR is essentially any other request, if you can't put it behind a barrier (authorization for example) it can be requested. There are *tricks* you can do to make it harder, though. – alex Mar 17 '11 at 00:55
  • Lookup 'anti-forgery token' – JulianM Jan 15 '16 at 00:22

4 Answers4

33

You can't prevent people from copying your client code or replaying network traffic.

Thanks to the same origin policy, other web apps can't access your API from the client. They will have to proxy their requests via the server, meaning these requests will come from a handful of easily identified IP addresses, which you can temporarily blacklist.

As for desktop and mobile apps, there's not much you can do. My advice is to not worry about them until they're a problem.

That said, it doesn't hurt to be prepared. If you want to avoid expensive legal battles, one thing you can do is change your API method signatures from time to time. Leaching apps can be fixed, but their reputation will steadily decline.

Richard Poole
  • 3,946
  • 23
  • 29
6

Authentication doesn't prevent abuse of your API's either. As long as the client can correctly authenticate with your system, he can use any client he / she chooses. Only the case where the client and the server are both secure and the connection is secure can you avoid abuse.

If the problem is abuse, then a simple throttling solution may be adequate.

Kim E
  • 324
  • 2
  • 5
3

If your client has code that is hidden from snoopers, could you not do as you suggested, use salts, ip address and time based values, encrypt them and then do the same on the server end? This is basically what mod_auth_tkt does, and it works well. Or would that constitute authentication?

Oskar Austegard
  • 4,599
  • 4
  • 36
  • 50
  • Ultimately though what you're sending to the browser is either code or secrets, yeah? In either case, I can see that now and use it in my unauthorized client app. I do get that this adds layers of obscurity which helps; I was just wondering if there was a "real" secure way. – Aseem Kishore Mar 17 '11 at 04:13
  • Yes, and nyamaybe... If you base your token on IP address AND time, then the unauthorized client has to be behind the same NAT, or know and spoof your IP address, AND he has to do it within the time-window you set. Anyone who does not know your valid IP would also have to know your secret. It can most certainly be done, but I would imagine outside a university campus (and Starbucks) there'd be little abuse. - Obviously this is not SECURE - as in I would never base anything involving a lot of value on this, but it may be enough to deter would-be hackers. – Oskar Austegard Mar 17 '11 at 18:45
  • Incidentally the SAS "security" mechanism for Azure public storage blobs uses ONLY the timestamp (and secret) - and many mod_auth_tkt implementations don't use the IP address either... – Oskar Austegard Mar 17 '11 at 18:46
  • How can you base a token on IP address though if your web app can be used by anyone? I'm guessing this is why Azure blob storage uses only timestamps. Sticking to that example, if you wanted to display an image in blob storage protected this way _on a webpage_, how can you possibly prevent an iPhone app from displaying that same image? I could just load your webpage in a hidden UIWebView, grab the image URL in the HTML, and use it in my app. – Aseem Kishore Mar 17 '11 at 19:33
  • 1
    Put another way: how can you prevent any iPhone app from using your API by pretending it's a web browser (spoofing the WebKit User-Agent) making the request from your web page (spoofing the Referer) on some random user's computer (so IP address can't be used)? – Aseem Kishore Mar 17 '11 at 19:35
2

Without an API key or some form of authorisation, you will be fighting a losing battle trying to keep unauthorised clients off your service.

You can sniff multiple things, but hard truth is most are easily forged.

Do you control the other web service? Also, if your web app (http://example.com/) accesses the API (http://api.example.com/) via XHR or JSONP, could you proxy the data on your server by using a library such as cURL to get the data, and then make it available on your site. You could then control the access to it any way you see fit.

alex
  • 479,566
  • 201
  • 878
  • 984
  • 1
    I'm sorry, I don't follow. How would you have an API key if you're making the request from client to server? (i.e. Anyone can open up Fiddler and sniff your API key.) I also don't understand how proxying through your own server would help. Change the example API endpoint to http://example.com/api and the situation remains the same. – Aseem Kishore Mar 17 '11 at 00:40
  • Well if you proxy through your server, you *can* use authentication or whatever you want to pass the info back. – alex Mar 17 '11 at 00:42
  • I apologize if I'm being dense, but what kind of authentication can you do? The app is anonymous, and any hacker can still use Fiddler to inspect the request/response. – Aseem Kishore Mar 17 '11 at 00:48
  • @Aseem I don't think you are being dense, you are asking the right questions. You can make things more difficult by requiring a nonce to be sent with each request, which is created by the parent HTTP request (i.e. XHR sends it on). Though I'm making assumptions about your service and how it works. – alex Mar 17 '11 at 00:51
  • 1
    But can't I just load the webpage in a hidden UIWebView to get this nonce? – Aseem Kishore Mar 17 '11 at 04:11