
Ask HN: Safe? API Keys in Your JavaScript Client. - junto
When building Single Page Apps with whatever-flavour-of-the-moment JavaScript framework, how do you go about securing access to API keys for your application?<p>This is separate to user authentication. I&#x27;m talking about allowing application A and only application A to access your REST web services.<p>Traditionally I&#x27;ve used an API key in server side apps, but in a client-side app, that API key is there for all to see and abuse.<p>This must be a common problem. How have other companies dealt with this problem? More to the point, when all of the REST requests require authentication, is it even a problem?
======
Someone1234
As others have said any API key you send down is open to scrutiny.

The only way to get around it is if you dynamically generate the single page
app API key, this somewhat negates the benefit of even doing a single page app
(e.g. being able to store the entire "site" on a CDN or something like S3).
Also being able to store it offline via Application Cache.

If you can generate the page you can have the generator script take the
client's IP and an expiration time (e.g. +1 day), and then encrypt it using
strong modern encryption (e.g. AES 256). The encrypted string is the "API
key." The single page app then sends it to your REST service which decrypts it
using the same encryption key, and checks the IP address against the
requester, and the time against the expiration time.

If someone wanted to abuse your REST API they would have to route API requests
through their own servers, which would then have to make a request for your
single page app, extract the encrypted key, and then make the endpoint REST
API request on the client's behalf. This is however easy to detect, just by
looking at the same IP(s) connecting over and over.

Plus counter-measures to abuse would be easy to implement and likely effect.

But ultimately this breaks the whole single page application concept
completely, and when it is all said and done you may have well have just saved
yourself the headache and keep the API key server side. If you're using a
third party REST service then everything I said above is irrelevant.

PS - This comment has so many caveats that it is barely useful.

------
peri
Unfortunately, good advice on this is going to be very hard to receive on
hn/reddit etc. Discussions of how to do this properly require a lot of fine
details. A good introduction to this would be via the link posted by mooreds:
[http://craphound.com/msftdrm.txt](http://craphound.com/msftdrm.txt)

Moxie Marlinspike's older post on the cryptographic doom principle, at
[http://www.thoughtcrime.org/blog/the-cryptographic-doom-
prin...](http://www.thoughtcrime.org/blog/the-cryptographic-doom-principle/)
also covers some of the basics.

You're much, much better off getting expert advice on this from folks familiar
with your SPA/JS Framework.

~~~
junto
I've been trying to get my head around OAuth2 to see if anything in that is
actually useful for this purposes. As far as I can see, 2-legged OAuth2 I.e.
"Resource Owner Password Credentials Grant flow" is the type of flow I need,
but it doesn't solve the malicious application problem.

~~~
peri
You need to talk to someone who will consult with you professionally to get
good answers to this question, sorry.

------
garethsprice
For third party APIs we need to expose (eg. paid geolocation service, or
social network integration), we've taken the approach of proxying requests
through a server-side component.

The server-side component takes requests from the client, provides some
authorization and rate limiting, and passes through the request to the remote
API with the secret key being stored server-side.

For authenticating requests we typically check the Referer header (spoofable)
and a rate limiter that aims to prevent automated queries but allow
manual/regular use of the app (eg. allow 1 request per 1000ms).

Where the application logic exists client-side it will never be possible to
completely encrypt anything, only temporarily obfuscate. Eventually you're
forced to send a request to the remote server from an arbitrary IP that can be
captured and replayed.

If it's your own API, and it requires authentication, then what behavior are
you trying to prevent? If it's scraping, rate limiting is your friend. If it's
unauthorized client creation, header checks will help (but are all spoofable).
Keeping a good audit trail of requests will help to identify and close holes
when they appear.

~~~
junto
I have to admit that this is my thoughts too, defensive and watchful, but no
panacea.

I'm interested primarily in mobile and web client accessing my own REST API.
Users have to be logged in to do anything anyway but it doesn't stop someone
who has a valid login from writing another application and abusing the system.

Like you said, you just need to be vigilant.

------
mooreds
In general, this is hard to do. This is because, as you say, the recipient can
reverse engineer anything you send down to the client.

See [http://craphound.com/msftdrm.txt](http://craphound.com/msftdrm.txt):

> In DRM, the attacker is _also the recipient_. It's not Alice and Bob and
> Carol, it's just Alice and Bob.

What applies to DRM applies to your webapp as well.

The best you can do is make this inconvenient: lock it down by IP range if you
can. Make the javascript hard to reverse engineer (there are encryption tools
out there). Have the API ask a question only a user would know. Password
protect access to the app before you ever send javascript which accesses your
web service. Do all this over SSL.

~~~
peri
This is a great answer, but it's also very important to remember that the IP
range you're locking down to may not be the CIDR block you think it is if
there are BGP or rDNS shenanigans occurring.

~~~
mooreds
Sure, IP address is just one more obstacle, but one that is entirely
surmountable for a determined attacker.

~~~
peri
I think that in my threat models "mistaken BGP entry" is not something that
happens because of determined attackers, it's something that happens all the
time because people is people.

------
thoman23
I'm building a SPA with a REST backend, and I don't think there's anyway
around this. It seems fundamentally if you are exposing your API over HTTP,
then it will be accessible. All of my API actions are behind an authentication
and authorization layer, but they are still unavoidably accessible once a user
has authenticated. Similarly I can write a standalone client that logs in to
Facebook and then do whatever I want with the data returned to me over HTTP.

------
mrwnmonm
what about this
[http://security.stackexchange.com/a/19625](http://security.stackexchange.com/a/19625)

~~~
kevan
As long as you're able to share sessions between services I think that would
work. If you have multiple backend systems it may take some work to get
session sharing implemented.

------
mrwnmonm
is this possible? i thought that there is no way to do this

