31

We're building a public single page app in JavaScript that talks to a back-end REST service. What we want is for that REST-service to be only accessible from the single page app.

Since it's a public website, we can't / don't want the user to enter authentication details. Any normal authentication mechanism won't work either since any secrets stored in JS are legible to anyone.

I think it's impossible to secure the REST service, since it basically has to be public, but I was wondering if anyone has an idea how you would prevent someone from building a script and reproduce our application using our REST api.

Kenneth
  • 413
  • 1
  • 4
  • 6
  • 1
    So, your question is about preventing someone from copying your site? – schroeder May 15 '14 at 22:41
  • Not really, the question is about preventing someone to use our REST api. They could make a copy of our site (in terms of functionality) or use the data for other purposes – Kenneth May 15 '14 at 22:49
  • Are you concerned about use of the API from non-JS applications, or just a browser-based clone? – David May 16 '14 at 02:08
  • Basically from anywhere. For JS apps we could prevent CORS, but anyone could write a small app that accesses our data – Kenneth May 16 '14 at 12:39
  • Hi @Kenneth, what did you end up to do? I am in the same boat as some of the developers using our APIs in their one-page js only and even with token everyone can see it and use it! I appreciate to see what have you done to minimise the risk and outside usage. – Maziyar Oct 12 '15 at 21:57

3 Answers3

12

If this is for native apps, you can try the following,

  1. Store an access key in your app bundle. Nobody other than app owner (yourself) can have this.
  2. Change your API so that only requests with the access key set in header will succeed.
  3. Use HTTPS so that nobody can read the encrypted access key.

If you don’t use HTTPS, you can still manually hash the access key with something in the header (only your server and app logic knows how) so that man in the middle can’t pretend to be your app.

If this is for pure web apps,

I would first suggest wrapping the pure web app inside a native app (a.k.a. Hybrid app) so that you can achieve the protection outlined above, by bundling a secret key inside the app. Developing a native app with a single web view inside shouldn't cost too much.

However, if that is not possible, so your app remains a pure web app - here is a potential option,

  1. When server serves the web app, supply an access key.
  2. When the web app makes API call it needs to supply a hashed version of the access key.
  3. How your web app hashes depends on logic that are implemented in minified+obfuscated codes.
  4. Your backend API then validate the hash by applying the same hidden logic to the stored access key to calculate the hash and see if it matches.
  5. You can change the hidden logic and access key as frequent as needed to reduce the chance of someone getting the right hash.

This is of course not bullet-proof but as you know, there is no perfect security and this probably achieves the purpose (and hopefully fits the bill). I would say going hybrid is more cost-effective though.

Daniel
  • 221
  • 1
  • 5
  • Neat and simple and it makes sense to me! But the access key ought to be shared with clients who will legitimately want to use the API. So it may be simple but maybe not so easy to implement? Nice idea though – dozer May 26 '14 at 09:51
  • Our app is not a native app, it's a web app in JS. Step 1 is impossible since the code is out in the public. – Kenneth May 26 '14 at 10:11
  • Hi @Kenneth, sorry I didn't realise it's pure web app - thought it was a hybrid app where a native app has a web view inside. Nevertheless, it's a good challenge and I came up with something - see edited answer. – Daniel May 26 '14 at 14:07
  • Hi @dozer if this was for native apps, the access key would be bundled with the native app source codes. All legitimate native app clients would share the same source codes with this access key. – Daniel May 26 '14 at 14:11
  • 1
    Thanks for the answer. However, in the end, this is just security through obscurity, because the only thing a potential abuser would need to know is the fact there's a hashing mechanism, and then extract the hashing from the minified/obfuscated code. I agree that it's more difficult to abuse the API, but it's not bulletproof, which is what I was looking for (and I think is impossible, since it is after all a public website). Thanks for the effort though. – Kenneth May 26 '14 at 15:12
  • That's true, you won't have true security in this case. Hmm, perhaps one way to bring it closer, is if you can automate that obscurity in the backend and change it fast enough so that realistically it's unlikely for anyone to calculate the hash _in time_. Anyway, fair enough. :] – Daniel May 26 '14 at 15:32
9

The first thought that comes to mind is either to use sessions or setup something on your page to log the IPs of incoming connections and only allow the REST API to respond to IPs that have recently accessed your main page. This won't prevent all cases, but it does mean that someone has to at least be periodically accessing the main site to make use of the REST API.

Fundamentally though, if users aren't required to authenticate, then there is nothing to prevent a screen ripper from effectively pulling data from your site. Business rules should be enforced by the REST API and so the REST API should effectively be your web site and the page using it should simply be providing formatting for the display.

AJ Henderson
  • 41,816
  • 5
  • 63
  • 110
  • Indeed, that was what I was thinking. We could implement some measures that will make it more difficult to access but nothing to completely prevent it. – Kenneth May 16 '14 at 14:19
0

This might help. There are many thigns you can do secure your rest service. One is CORS and using PUT/Delete as these headers can't be set cross domain. http://www.nsa.gov/ia/_files/support/guidelines_implementation_rest.pdf

  • 2
    The problem is not securing the REST api. The problem is securing it while still have it accessible publicly, but only to exactly one JS app. CORS won't help if you access the api outside of the browser – Kenneth May 19 '14 at 08:40