Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Ask HN: Safe? API Keys in Your JavaScript Client.
12 points by junto on Jan 23, 2015 | hide | past | favorite | 15 comments
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?

This is separate to user authentication. I'm talking about allowing application A and only application A to access your REST web services.

Traditionally I'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.

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?



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.


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

Moxie Marlinspike's older post on the cryptographic doom principle, at http://www.thoughtcrime.org/blog/the-cryptographic-doom-prin... 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.


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.


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


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.


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.


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:

> 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.


This doesn't even make it hard anymore - voluntary or not everything's a bit of an open API when you can use headless browsing to automate interacting with websites and generate legitimately constructed requests.

CAPTCHA-ish 'human authentication' for API requests would make things hard.


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.


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


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.


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.



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.


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




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: