What is the point of the Javascript client key? - javascript

Part 1 of the Parse Security Series states
The client key is given out to your users, so anything that can be done with just the client key is doable by the general public, even malicious hackers.
...so why does the client key exist?
I understand that a logged-in user will get special privileges, but if some site functionality is legitimately available to the general public, why is there a key at all?

I think "client key" is a legacy term from early parse.com. A better name for it now would be something like "iOS and Android SDK identifier". When it was once an iOS sdk/backend, the client key was kept in relative obscurity in compiled source.
This was undone by the addition of javascript. Speculating here, but parse probably wanted to allow existing developers with shipped apps to add JS without compromising security they had assumed with the original. So parse provided a newly titled and distinct "javascript key". Notice how many "keys" there are now ... more like client type identifiers than keys in any security sense of the term.

It's not possible to withhold credentials from your users. They have to connect to your application somehow. The mere act of accessing the Parse Backend requires it.
So what do you do?
In my case, I don't give the Parse key out in the client app; rather I'm wrapping it inside of something like AWS API Gateway, which means I can keep users from accessing the Parse backend directly. Yes, that means my users will have an IAM role; but I can lock that down and revoke as needed (and use AWS's IAM API to do so). I also have rate limiting abilities that would otherwise cause Parse to just silently drop requests.
You also don't have to actually give clients the JavaScript key -- you could store it in your Node.js application and simply manage access control yourself. Another layer of indirection always solves the issue.

Related

Where to store API key in ReactJS?

I quick question!
I have a webapp that only fetches data from an API so i dont have i backend part. My question is where do you keep your API key? Accordingly to React docs you should not store API keys in the app so how do you manage this when you have an webapp that consumes an API and you have to use the API key in your get requests?
Let's do a bit of explanation, so you connect the dots and design it more robustly. There are two (three) places where to store it in the end:
frontend (your React application)
backend (your server)
third-party service
TL;DR: use non-frontend solution + rate limiting to a registered user and have the registration step secured properly (+ captcha).
Frontend
Storing anything on the frontend side is mostly a bad idea, unless you're completely sure you can allow such data to be exposed - constants, names, icons, maybe some URLs so you don't have it hardcoded in the JS files.
Your "compiled" ReactJS (or any other framework) when built is just a slightly mangled (minified/transpiled/etc etc) JavaScript, but for that to work the client has to retrieve it and have it executed in the browser. Therefore before the ReactJS application even starts, there are 1+ requests downloading the JavaScript code and other parts of the application depending on the framework.
Those you can see in the network monitoring tab in any modern browser or simply use Wireshark (unless encrypted, then it's a little bit annoying) or a local proxy if using a less sane browser.
After retrieval you can simply try Ctrl+F or any online deminifier/deobfuscator if you don't know how to do it yourself and you can retrieve the key.
Implications when retrieved
I can impersonate you for the service that issues the API key
I can lock your key/account by calling too often (just for fun or to retrieve some info)
I can use your web for scraping while not needing to pay for the API key (if paid) or to register to such service vendor
If it's per-request API key and there's some limitation that would make it cost you money, I can just run some silly while (true) { callYourApi() } via a service to make me anonymous just to make it cost you
Depending on the API key and how serious you intend to approach this problem, you might utilize the .env file for development purposes only. Though you should never ever store an API key in the frontend unless you explicitly have to store it in there (e.g. maps) because it's mostly a very stupid idea and allows anyone to misuse it.
Backend
Your server, if properly configured and secured, will store the key anywhere which isn't accessible by simply path traversing (if in a file) or scraping (if you attempt to retrieve the key to execute on the frontend part).
Therefore the most sane and secure way would be to retrieve the data (of any service) by having either a custom API or a scheduled script collecting the data, which when your frontend gets called will be able to retrieve as pre-rendered or already fetched, thus no key needed for that case.
However! There's a trick to that. If you design your custom API as /api/<key>=123 or /api/<param> and you use that parameter for the original API to filter on frontend, the attacker couldn't care less for the API key because you've already created an API for free and made it public and unsecure.
So GET /yourapi/<my data> and API key for free without even needing to have one displayed.
How to do it safely? Two simple approaches:
pre-rendering data to HTML
You then fetch with frontend and just display - but this one can be scraped, it's just a bit annoying if more complex, but that's it. Server-side rendering sounds nice, but doesn't really work for this case. It should be mostly used to make the frontend fast or to template the views, but never for security purposes as the silver bullet solution (because it doesn't work that way).
rate limiting + CORS + account management
with rate limiting you make sure that a user (preferably you have that API called only after a user is logged in) can call that API only e.g. 10 times within 1 hour and with CORS you make sure it's callable only by your frontend.
It's not a silver bullet either, anybody with a little bit of brain can simply scrape your API locally thus go around CORS, but the rate limit will still hit hard, if you forbid registering more than 1 user from a single IP or if you require a phone number for verification. And add some annoying captcha, so it's problematic to automate for some people.
Still it can be attacked and misused, but it's painful unless you allow the same phone number (or any other ID less comfortable to get / requiring effort to get) to be used multiple times, so it'll make the most incompetent people go away... and the remaining ones, well, they'd play with your website anyway, so have a proper security assessment / harden your server if you maintain it alone.
Third-party
It's like 2., but you don't maintain the "low-level" server part, because the third-party is then managing it for you, you just need to specify conditions under which it'll be called. This applies to Firebase or Supabase which kind of behaves like a separate backend, but can have multiple modules (for FB, 1, 2).
Thus you'd use Firebase functions (or other alternatives), where you'd have your key e.g. even hardcoded and the client (browser) wouldn't have any access to that, add a limit, cors, perhaps some user registration limit and you're kind of done.
Note: Any domain, IP, region, phone number restrictions can be bypassed, so do not rely on them. It's just a mean to require effort when misusing your website for something different than you intended.
domain: curl http(s)://yourweb/path -H "Host: spoofed-domain"
region or IP: proxy, VPN, Tor, I2P, just somebody else's computer/server + ssh, some random WiFi
phone number: can go to a local shop and buy 10 fresh ones if I wanted to
It's more of a recommendation for them to keep your API keys server-side, and let your web app communicate with your server. Otherwise malicious users could easily steal your API key and use it for whatever.
If you think it isn't much of a security risk if your key gets (scratch that, is) compromised, that's fine then, you can just keep it in your webapp. Really depends on your use case and what that API key is for.
The only way to do this without exposing your API keys in your client app is to create a backend and serve the client app from the backend app as stated by Kelvin Schoofs and Peter Badida answers above (or use a third party service such as AWS Credential Vault). I suggest you use Node Express library for a backend as this will handle a lot of the boiler plate code for you. There are plenty of tutorials online for this.
Using a dotenv file as suggested by a few other users will only hide your API code from version sharing tools like Git (because you can ignore the dotenv in gitignore). It is very important that you understand the process of dotenv with a react app. Any user who opens the Dev console in their browser can view your exposed API keys in the static HTML.
Create a dotenv file and store all secret and API keys. Make sure to use REACT_APP_ before every variable.
DOCS: https://create-react-app.dev/docs/adding-custom-environment-variables/
dotenv package: https://www.npmjs.com/package/dotenv

Where to store sentitive data?

I have 2 NodeJS apps and they exchange some data. The data is encrypted via AES.
At the moment the AES KEY is hardcoded in the javascript code at the client and at the server.
The question is: What is best practice? Where do i store the keys at the client/server? Both apps are 100% console apps. (no user / browser interaction).
UPDATE: I used the terms client/server. Because - to me and regarding the app. logic its a server/client relation. BUT but the apps. are literally running on two separate AWS server-instance. I can even make IP restrictions between the two instances. So nobody should have access to the instances other that the AWS RDP account and through the ports the two instances are communication via...
They exchange data via a web socket connection and some times they also access a HTTP API running at a third instance... thats all...so is it safe enough to have the keys hardcoded or where should i place them?
You should have a random key instead of the fix one, because if anyone gets hold of it, then they can use a man in the middle attack.
Try generating a key on the server and send it to the client. On the client you store this somewhere (preferably in a scope) and when you need to read or write messages, then you can simply use that.
Additionally, you should have a different key for every client and if possible, you should change the keys regularly.
Everything is pretty much open source if you know how to convert it back, even with obfuscators (you can almost always deobfuscate). Having a hard coded key is as useful, as not having a key at all.

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.

How can you secure a JavaScript application's API calls?

I have a JavaScript application.
It's built with jQuery.
It uses $.get() to pull JSON data from a server, and uses the data to load a puzzle.
I want to distribute the JavaScript application to clients, and make it easy for them to install.
I'd like it to simply give them a JavaScript block they can drop into their page, and it will interact with my API.
I'm not passing sensitive data, any my API is protecting the database from SQL injection, etc.
I just want to try to prevent unauthorized use of my API, and I can't think of a way to do that with JavaScript, since anyone with a DOM inspector can scrape any credentials from any variables or can monitor any server traffic POST or GET data...
Would it be possible to authenticate the referrer on the other side?
I know that's not bulletproof, but it's not sensitive data. I just want to reduce the unauthorized use as much as possible..
Any ideas?
note: I know obfuscating an API key or something is futile, I'm wondering what other controls I could put in place other than a traditional key to identify the caller to the API.. I have full control over the API itself so I could do anything on that side of things...
JavaScript authentication has holes
With JavaScript, just about any authentication system is going to have holes, simply because the code runs directly in the browser and can be seen by anyone (as can the network calls). So there are a couple of things you can try, depending on your situation.
IP whitelisting
If you are distributing this application to a small subset of clients, and you know exactly where they will be accessing it from, you could use IP whitelisting. This really is the only way to completely secure the API. However this method is very cumbersome, since with every new client you have to update the API whitelist, and considering what you're talking about here probably not what you're looking for (but I mention it just because it is a possibility).
Access tokens
Another method is access tokens. This is a common method used by sites such as Facebook. There are two methods to do this. One is to just give each client a secret key. You can have the same secret key for everyone, but this is not very secure. Having a different secret key for everyone allows you to not only track usage, but also revoke access privs if necessary.
The first method for access tokens is to just give it inside the JS client. However this means that anyone who looks at the source will be able to access your key, and make requests using it.
The second method is to have the secret key stored somewhere on the SERVER of the website where your client runs. This server can then make a server-to-server call using that key to obtain a temporary session token. People will still be able to access the temporary session token via the front-end, but they will have to access this site first in order to get it (this allows you to pass off responsibility for handling this to the website operator) and the token will eventually expire. However this means there needs to be some server-side code, and the app won't just be a drag and drop thing.
For the method given above you can also look into things like OAuth, to avoid re-inventing the wheel.
Whitelist hard-cap
Another possible thing using IPs is to set a hard-cap on either how often or how much per day a specific IP can hit the whitelist. Though you may run into problems with users who REALLY like the puzzles, this will prevent some of the potential abuse.

Browser-based encryption/decryption with private key from browser keystore

My situation:
Medical staff wants to enter sensitive data of patients into a web browser (!) in order to store it to some database and later retrieve it again.
These data are not allowed to be seen by anyone else except the medical staff itself. This means that it must be encrypted using some secret token before it is transferred to the server. It also means that neither IT staff (having access to the server/database) nor anyone else should be able to decrypt it without the secret token. (If the token is lost, the data would never be accessible anymore.)
No additional software should be installed on the client machine, except some token (e.g., a private key) that one would export once and import it into all browsers from which data access should be granted.
So my question is:
Is there a way to encrypt/decrypt data on the client-side (e.g., using JavaScript) using some secret browser token that can be exchanged between browsers easily (I.e., exported/imported similar to X.509 certificates)?
If not, which alternative solutions would be possible? Since conditions 1 and 2 are mandatory, only condition 3 may be modified, if necessary. However, still as little installation effort as possible should be necessary on the client-side.
EDIT: SSL is obviously only part of the answer to this question!
Take a look at Web-browser encryption of personal health information, whose "Abstract" section seems to describe your same problem. However, their "passcode" that generates the encryption key must be shared, which wouldn't let you differentiate medial staff.
We describe a system for remote data entry that allows the data that
would identify the patient to be encrypted in the web browser of the
person entering the data. These data cannot be decrypted on the server
by the staff at the data center but can be decrypted by the person
entering the data or their delegate. We developed this system to solve
a problem that arose in the context of clinical research, but it is
applicable in a range of situations where sensitive information is
stored and updated in a database and it is necessary to ensure that it
cannot be viewed by any except those intentionally given access.
There's a javascript implementation of AES encryption which encrypts the plaintext in the browser. If you build something around those tools, the server side would store only the encrypted text and would not have the passphrase.
http://www.fourmilab.ch/javascrypt/
Shouldn't require any extra installation on the client side, but probably will require some development effort to get the user experience right.
Due to ProtonMail's efforts, there is now an open source PrivateKey implementation in the browser at: https://openpgpjs.org/
This has had multiple security audits and is the basis of protonmail.com, so it has a fairly good records and maintainer in place. They also have a good summary of important security browser models.
The Web Crypto API has pretty good support in all modern browsers. It supports many algorithms, both symmetric and public key. With a good reminder for the user to keep their keys secure and may be backed up somewhere else, this should be the way to go.

Categories

Resources