Prevent key leak in HTTP GET requests - javascript

There's lots of general info about preventing API key leaks, but I'm having trouble finding proper procedure specifically for making an HTTP GET request with an API key as a parameter. Any user can easily inspect the request and grab an app's private API key as far as I can tell.
Is there any way to safely make GET requests? I'd use something other than GET if it was made available by the third party API. Might just be bad design.
Example from an app I'm working on. When I make a GET request to a third party API, my API key can easily be seen in the inspector:
Code:
const response = await fetch('https://www.someexampleimadeup.com?var=something&key=LOOKITSMYPRIVATEKEY'
Inspector:

You are right.
If you pass a private API key with your GET request initiated by client-side javascript, you are exposing the key. And no, there's no way around it if you want to do this client-side (if you are fetching the API from a javascript file that runs on the browser).
That's because by definition HTTP requests messages are composed of textual information encoded in ASCII (as properly explained in this MDN article). All HTTP requests of any protocol are always available to the user of the browser who initiated the request, even if you use HTTPS.
It's important to address that the simple fact of your private API key being present on client-side javascript code makes it insecure - public.
If running server-side javascript is an option for you, something like a Node.js backend server, you can fetch your server fetch("https://yourserver.com/resource"), and then your server can fetch the API with the private key fetch('https://api.com/?api_key=XXXXX'). Now your backend server is the middle man (or the black box) responsible for getting the API data without exposing the private key.
You won't be exposing the key because the user only knows about the GET request to your server and the data you choose to return. As well, as you have control over your server, you can choose not to expose your private API key by not serving the file in which it is written.
In Node.js webservers, you usually store your API key in a ".env" file PRIVATE_API_KEY=XXXXXXX, which is not served. This file is then added to the rules present in .gitignore, to prevent it from being pushed to any public repository. With the help of a node package like dotenv, you can access it on your code as a property of the process.env object process.env.PRIVATE_API_KEY (some examples in their npm page).

In this case, the key will not be leaked over the network because the request uses TLS (https://). This is because the querystring is entirely in the HTTP request, whose data is entirely sent across a secure connection.
However, it is never safe to use private API keys in a web client—with any kind of request, GET or otherwise. The frontend is rendered and run entirely on the machines of your users, so any information you put in that HTML or JavaScript can be seen. If the API you use only provides private API keys, then any requests you make must be done on your own server.
On the other hand, some API keys are meant to be used on the client. For example, consider the Google Maps API. In this, the only risk associated with having a visible API key is the fact that other users could use that key for their own websites and incur charges. Google mitigates this by allowing developers to specify allowed origins: that is, it limits what domains can use the key.

Related

api key security for WebAssembly application

I know it's always a bad idea to put api key in frontend.
We are designing a WebAssembly application which authenticates through Javascript api call. Other users can get the WebAssembly binary which we provide and build their own website if they have the api key.
To alleviate the misuse, each key has to bind to user specified domain name. (Just like how Google does, which I feel is not a very secure way...)
Even with HTTPS, in order to address the concern which client may modify the api response at JS side, which is going to pass into WebAssembly app to determine the authentication status, server side signs the response and WebAssembly app embeds server public key to verify the response which is not being modified after receiving at JS side.
So the flow would be...
Start WebAssembly app with api key
-> JS side call auth api with key as parameter and referer
-> server checks domain name (referer) and key. Return signed response which can be verified only by WebAssembly app (not JS client).
-> If ok, start the WebAssembly app
However referer is spoofable. In this case we are thinking getting domain name from WebAssembly side then encrypt domain name with key to generate one obfuscated url parameter. The server then will be able to decrypt that parameter to get the correct key and domain name.
I am wondering if this is the best way to do it, or we are just making things more complicated without gaining real security.

RESTful API write security

I've recently started using modern front end technologies like React/Angular and as a result have started using tools like JSON Server to recreate dummy restful db interactions.
My understanding is that most rest api's authenticate via some kind of token and secret that is either passed as part of the url or as a header. This seems fine for retrieving data, but is it not risky exposing these login credentials in a front end language like JS when writing is possible?
My thinking is that all it would take is a simple view source for somebody to steal my token/secret and potentially start populating my db with data.
In the problem that you describe the client (browser) has the login credentials because the server provide them. There is no "exposing" as the credentials are already exposed. Exposing your credentials to every client means that there is no security.
When we talk about security we consider as a client the browser not the real person that operates the browser. As you said, the real person can access all the browser's data.
To secure your API the secret key must be kept secret. This means that each client has a different key and uses it to get their data/services from your RESTfull server.
In a simple senario this key can be used/managed like the session id.
The client should first pass through an authorization process (login maybe) and then a temporary key can be generated for the client's session.
Generally, a key is converted to rights. If every client by default has the key, everyone has the default rights, so you may also remove the key and set the default rights to every request.
A client that you don't want to have full access to your db should have a key that gives him limited access to your db.
On the other hand, if the client provides the key, this is secure. For example a php code on a server that uses the secret key for accessing your API.

How can I avoid hard-coding sensitive values in JavaScript?

I'm working on putting AngularJS on top of an existing Rails API. Part of the authentication process involves passing a "secret key".
I need to pass the secret key in order to authenticate, but I can't think of any way to pass the secret key without actually including it somewhere in the JavaScript.
I imagine this is either a common challenge or we're doing some things way wrong. How can I avoid hard-coding this key?
Usually what I have seen is that the client requests a user-specific token from the API and then sends it back over HTTPS on a per request basis.
If the secret key is shared across all clients then you have to do more work. One way to handle this would be to create a proxy that generates and accepts user-specific tokens on the frontend and uses the shared key on the backend. The JS would talk to the proxy.
There is no possible way to do this without the user being able to figure it out. Even if you don't include it in the js (which is almost impossible in itself), anyone can just use their browser devtools to inspect the network requests and see the key that way.

Web services API Keys and Ajax - Securing the Key

This is probably a generic security question, but I thought I'd ask in the realm of what I'm developing.
The scenario is: A web service (WCF Web Api) that uses an API Key to validate and tell me who the user is, and a mix of jQuery and application on the front ends.
On the one hand, the traffic can be https so it cannot be inspected, but if I use the same key per user (say a guid), and I am using it in both then there's the chance it could be taken and someone could impersonate the user.
If I implement something akin to OAuth, then a user and a per-app key is generated, and that could work - but still for the jQuery side I would need the app API key in the javascript.
This would only be a problem if someone was on the actual computer and did a view-source.
What should I do?
md5 or encrypt the key somehow?
Put the key in a session variable, then when using ajax retrieve it?
Get over it, it's not that big a deal/problem.
I'm sure it's probably a common problem - so any pointers would be welcome.
To make this clearer - this is my API I have written that I am querying against, not a google, etc. So I can do per session tokens, etc, I'm just trying to work out the best way to secure the client side tokens/keys that I would use.
I'm being a bit overly cautious here, but just using this to learn.
(I suggest tagging this post "security".)
First, you should be clear about what you're protecting against. Can you trust the client at all? A crafty user could stick a Greasemonkey script on your page and call exactly the code that your UI calls to send requests. Hiding everything in a Javascript closure only means you need a debugger; it doesn't make an attack impossible. Firebug can trace HTTPS requests. Also consider a compromised client: is there a keylogger installed? Is the entire system secretly running virtualized so that an attacker can inspect any part of memory at any time at their leisure? Security when you're as exposed as a webapp is is really tricky.
Nonetheless, here are a few things for you to consider:
Consider not actually using keys but rather HMAC hashes of, e.g., a token you give immediately upon authentication.
DOM storage can be a bit harder to poke at than cookies.
Have a look at Google's implementation of OAuth 2 for an example security model. Basically you use tokens that are only valid for a limited time (and perhaps for a single IP address). That way even if the token is intercepted or cloned, it's only valid for a short length of time. Of course you need to be careful about what you do when the token runs out; could an attacker just do the same thing your code does and get a new valid token?
Don't neglect server-side security: even if your client should have checked before submitting the request, check again on the server if the user actually has permission to do what they're asking. In fact, this advice may obviate most of the above.
It depends on how the API key is used. API keys like that provided by Google are tied to the URL of the site originating the request; if you try and use the key on a site with an alternate URL then the service throws and error thus removing the need to protect the key on the client side.
Some basic API's however are tied to a client and can be used across multiple domains, so in this instance I have previously gone with the practice of wrapping this API in server side code and placing some restrictions on how the client can communicate with the local service and protecting the service.
My overall recommendation however would be to apply restrictions on the Web API around how keys can be used and thus removes the complications and necessity of trying to protect them on the client.
How about using jQuery to call server side code that handles communication with the API. If you are using MVC you can call a controller action that can contain the code and API key to hit your service and return a partial view (or even JSON) to your UX. If you are using web forms you could create an aspx page that will do the API communication in the code behind and then write content to the response stream for your UX to consume. Then your UX code can just contain some $.post() or $.load() calls to your server side code and both your API key and endpoint would be protected.
Generally in cases like this though you proxy requests through the server using 'AJAX' which verifies the browser making requests is authorized to do so. If you want to call the service directly from JavaScript, then you need some kind of token system like JSON Web Tokens (JWT) and you'll have to work out cross-domain issues if the service is located somewhere other than the current domain.
see http://blogs.msdn.com/b/rjacobs/archive/2010/06/14/how-to-do-api-key-verification-for-rest-services-in-net-4.aspx for more information
(How to do API Key Verification for REST Services in .NET 4)

Amazon SimpleDB Javascript interface possible?

I'm checking out amazon simpledb documentation. They mention only server side languages.
Is there anyway to insert data into the db directly from the client side without going through a server?
If not, how come?
Yes and no. Since you need to protect your secret key for AWS (hackers could use it to abuse your account), you can't authenticate requests in JS directly.
While you could create an implementation in JS, it would be inherently insecure. Practical for some internal uses, it could never be safely deployed (as that would expose your secret key). What you could do instead is use your server to authenticate the requests to SimpleDB and let the JS perform the actual request to Amazon. Though it's a bit roundabout, it would work.
The downside is that you'd need to do a bunch of processing on the client side. You're also likely fetching more data than your app consumes/outputs, so processing the data on the client instead of on the server would likely encounter more latency simply because you're transferring more data to the user and processing it more slowly.
Hope this helps
If not, how come?
Security. You authenticate to the DB with your developer account. Amazon does not know about your end users (which it would need to, in order to authenticate access directly from the browser). It is up to the application code to determine what end users are allowed to do and what not.
That said, there is the Javascript Scratchpad for Amazon SimpleDB sample application. It does access SimpleDB directly from the browser (you have to type in your AWS credendials).
SimeplDBAdmin is a Javascript/PHP based interface:
http://awsninja.com/2010/07/08/simpledbadmin-a-phpmyadmin-like-interface-for-amazon-simpledb/
The PHP side is a relay script[relay.php] which will pass the requests made from the Javascript client and send them on to the server, takes the response from the server and reformats it for the client. This is to easily get around the cross-domain problems with Javascript[if the web client had downloaded the web page containing the javascript code from www.example.com it will only allow javascript to connect back to www.example.com by default].
Everything else, including request signing, is done by the Javascript code.
Also note that Amazon has released a new beta service recently to allow you to setup sub-accounts under your Amazon account. The simpleDB protection is very basic[either on or off per account] but as it does provide some limited form of request tracking, it could be argued that using Javascript and giving each user their OWN userid and key for request signing is MORE secure. Having every user use the SAME userid and certificate would, of course, be insecure.
There is a free, pure JavaScript interface available. Please see https://chrome.google.com/webstore/detail/ddhigekdfabonefhiildaiccafacphgg
See this answer to the similar question on allowing secure, anonymous, read-only access to SimpleDB from untrusted clients: anonymous read with amazon simpledb .
Some variations from that answer:
don't set access policy to read-only. However, it allows fine grained control, so you may still wish to limit the kind of writes allowed
don't be anonymous. The AWS docs on token based auth and example apps show parallel paths: anonymous access or non-anonymous AWS/federated access with your credentials but without exposing your secret key.

Categories

Resources