How to handle public API Keys? - api

I see many APIs (e.g., stripe) that give both public and private keys to users; the former for front-end and the latter for back-end. How can you prevent someone from stealing/using the public (front-end) API keys? I've seen some people say you should have domain whitelisting, but those can be spoofed.

The point is that domains (origin) cannot be spoofed in a standard, unmodified browser. Sure, your api key can be used by others from non-browser clients, but what's the point, what would they gain, without your users' context? And they cannot use them in their own web project for their own users, because origin cannot be spoofed in a browser.
There is still some inherent risk (presented by attackers still being able to use these keys in non-browser clients), but there are usually also countermeasures on the providers' side to limit the impact of such abuse, and you should also design for this and always keep in mind that these keys are not actually secret. For example if the key is for client-side log collection, you must be aware that logs collected that way may not be authentic (can be forged by attackers), but they could also forge them on your website, because from their own browser they can send whatever they want.

Related

Is there a way to secure an API key on a frontend page?

My service allow any HTML documents to be converted to PDF using a POST request.
It is mostly used on the backend of my client's server and thus, the API key used for the communication is kept private.
Now, I'm thinking of a way to let my client's visitors be able to call my service on behalf of my client API key, without exposing this secure API Key.
My main issue here is security. If my client add an XHR POST requests that contains the API key, someone can take that API key and use it for their own purpose and abusing my client's account.
I could filter by domain, but this is easily spoofed so it's not possible.
I was wondering if there was a way to call a private service and be identified without risking its identity to be stolen, from the client ('s client) side?
If you're providing this sublet for authenticated users, then it's fairly trivial to give them unique keys (something that hashes their user ID or session against the API key and an initial timestamp, and checks it / logs it / looks for brutes before accessing the API). If you're doing it on the open web, without any kind of user authentication, then rate limiting gets very tricky indeed. Generally you'd want to use a combination of session hashes, IP address, operating system and browser data to create an anonymous profile that gets a temporary key on the frontend. One fairly solid way to do this is to force users through a CAPTCHA before serving a temporary key that allows them a limited number of uses of the permanent key. Any user whose ip/browser/session matches the existing attributes of a known client key is shunted to that one (and gets to skip the CAPTCHA); anyone who doesn't match an existing profile gets the CAPTCHA. That makes you a less attractive target for spoofing. On top of that, you should always rate-limit the entire thing, within a reasonable number of hits per day based on what kind of traffic you expect (or can afford), just so you don't have any surprises. This is the minimal security you'd want if your client's money is on the line every time their API key is used. It will require a simple database to store these "profiles", track usage, check for brutes and maintain the currently valid client keys. Client keys should always be expired regularly - either with a time diff against when they were created, or a regular cron process, or a maximum number of uses, etc.
One other thing I frequently do is rate-limit based on a curve. If I think 5 uses per minute is reasonable, for example, then after 5 uses in a minute from a session, each usage adds a delay of a fraction of a second * the number of uses in the last minute, squared, before the data is served.
The best answer would be to put this all behind a login system and secure that.
Assuming that you are using OAuth kind of system, In that case, make use of Access Token Mechanism that provides access to private API/User's data on behalf of User(Client) without exposing his/her credentials or API Key(Authentication key), also the access token can be expired based on the time/usage.
Example: The access token is generated against a single endpoint that can be the Html Conversion endpoint and will be expired once the action completion.
https://auth0.com/docs/tokens/access-token
And following blog post would be helpful to architect your authentication system
https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/
there is no good way to do front-end secure storage but my recommendation is :
is an API that used HMAC signing of requests in combination with OAuth authentication. The API key is actually a signing key. they key does not get transferred. The API key can still get found on the front-end but it becomes useless because you still need the OAuth token to send a valid request.
i know users will have to login in, but you can see this as an advantage because atleast you can log who is using the app by getting information from oauth.
please consider back-end secure storage!
You can use JWT tokens in my opinion. On the basis of username, password or any other info you can generate unique jwt tokens for different users.
Anyone can decipher these jwt tokens but not he unique security token.
If you want to add more more security to tokens, use JWE, encrypted web tokens.
More about these schemes can be found at https://medium.facilelogin.com/jwt-jws-and-jwe-for-not-so-dummies-b63310d201a3
Hashing is a decent option and should be done anyway, but for a fully secure method that wouldn't add too much complexity, you could simply abstract away from the authorization/API key by building your own API to interface with the API. This way you could both limit the kinds of things that can be done with the API key and also completely obscure the API key from the user
I don't think you should always go for user auth or JWT, it just doesn't fit all use cases. The idea of using a Captcha is interesting but also somewhat complex.
If complexity is not an issue I would rather use an infrastructure approach, I'm most familiar with AWS so I'll focus on that. Assuming you can change the host of your front end you can have your site hosted on an S3 bucket, served through a CDN, and create a proxy Lambda function that will hold the logic to call your API and store the API key as an encrypted environment variable. This Lambda you call through an API Gateway that can only be called by a specific IAM role which the S3 bucket also uses. You can also use a Cognito User Pool without authentication.
Going back to a simpler alternative the Captcha approach can be implemented as an attestation provider. I know of two services that do this, Firebase and KOR Connect. Due to Firebase using this approach only for their own resources as of the time of this writing I much rather use KOR Connect as it’s a very simple middleware that basically solves this issue. I won't go into detail about these services as it’s not the main concern of this topic but you can check the documentation their respective links.

what happens to JWT if someone gets my private and public key?

It seems to me that if my private and public key are compromised (which i use to sign and verify JWTs), that anyone can independently generate JWT tokens for themselves to use on my API?
Whereas on the other hand if I generated my own tokens myself, and stored a look-up table of 'one-way-hashed user id' => 'token', then if someone broke into my system, they would not be able to generate tokens to use on my API, and they would also not be able to use the tokens (because they would not know which token belonged to which user)
If someone breaks into your system and it is still secure, then you made a secure system; nothing to worry about.
with JWT, it appears to me that if someone breaks in, I do have something to worry about.
It seems to me that if my private and public key are compromised (which i use to sign and verify JWTs), that anyone can independently generate JWT tokens for themselves to use on my API?
Yes, that's correct.
Public keys are intended to be public and can be distributed.
On the other hand, private keys are supposed to be private and must be kept secure in your server. Anyone who has access to the private keys should be capable to issue tokens.
Disclosing your private key is a huge security breach.
It seems to me that if my private and public key are compromised (which i use to sign and verify JWTs), that anyone can independently generate JWT tokens for themselves to use on my API?
As also pointed out that you need to keep your Private Key Secure , the best way to keep it secure is to use an HSM for signing your data , in this case you can extend the JWT generator to sign the data through a crypto dll inside the HSM , this insures that the private key is never exposed outside the HSM
Whereas on the other hand if I generated my own tokens myself, and
stored a look-up table of 'one-way-hashed user id' => 'token',
Any one can generate your non-keyed hash. Secure hashes involved a private key which becomes a digital signature. Now we've come full circle, because that's exactly what a JWT token is.
Alternatively, you store them in a datastore, but now you must query this on every round trip. Most ticket(cookie)/token authentication systems use public key verification, which verifies the validity of the ticket/token without a database roundtrip.
If you store them in a datastore, now you must track expiration in the datastore as well. Tickets/tokens can have an expiration built into them. The nice thing about tickets/tokens is the client holds them. You can expire a session more quickly than the authentication. I.e. often you get a ticket that may allow you to be logged in for 2 hours, but the web server can expire your session in 10 minutes to reduce memory usage. When you access the web server in 15 minutes, it will see your ticket/token and see that it is still valid, and create a new session. This means at any point in time the server is tracking far fewer idle users.
JWT issuers are great for distributed systems, where authentication is shared. Rather than reimplement the authentication in every system, exposing multiple systems to the private key, as well as potential bugs in the authentication, we centralize it to one system. We can also leverage third party integrators that generate JWTs. All we need to do is get their public key for verifying the JWTs.
If someone breaks into your system and it is still secure, then you
made a secure system; nothing to worry about.
I have your list of nonces you were saving in your database now, and can login as anyone. I also likely have your connection strings, even if you're encrypting your application config, if I have root access then I can access the same key store that's used by the application to decrypt them. Now I get your username/passwords from your database and can login as anyone, regardless of what authentication scheme you use.
You'll be hard pressed to find a system that can still be secure after someone's gained root or physical access to the machine.
There's a small handful of systems that have purpose built hardware for storing keys and handle requests for encryption operations through an interface, thus ensuring the keys are protected at a hardware level and never accessed directly from software:
https://en.wikipedia.org/wiki/Hardware_security_module

How do 3rd party APIs prevent API Quote theft?

I am writing an app that uses a 3rd party API service (say Google Maps, segment-analytics etc...). All these apps give an API key that is supposed to be embedded in the JS code.
So anyone who can inspect the source knows the client key. How do these services prevent wrongful usage of that key.
Say someone calls these APIs with my key as many times as the daily allowed maximum API call limit, which will make the further actual API calls fail.
I know that Referrer Header can be used to check the request origin, but Referrer Header can be easily spoofed by a savvy user.
I don't know if there are any measures taken by the services. Seems like a very major problem.
Thanks in advance.
It is a risk, but it's not as bad as it may seem if the API provider is prepared.
The first thing to note is that such an API key is not used for authentication in the sense that it does not authenticate the caller (neither the application nor the enduser). It is only for things like rate limiting and tracking.
So really threats are similar to what you described, for example somebody using your API key and using up your quota. However, if that person is doing that from his own computer or network, all the malicious traffic is seen from his IP or IP range. If the API provider is smart and has good monitoring (like Google), they will not revoke/disable your API key but will filter or disregard the malicious traffic only.
So the attacker should be able to put up a website using your API key and get users to visit it. However, in this case the referer/origin headers cannot be spoofed, browsers won't normally allow Javascript to change the referer or the origin header in the request. So again, the API provider has a way to filter malicious traffic based on referer/origin.
The attacker would need access to many different clients, something like a botnet to make all those requests with your API key to use up your quota. This would probably work, but if an attacker can attack your site with distributed denial of service, your primary concern will probably not be your API keys.

Authenticating Requests From A Single Server

I'm working on a project which contains data belonging to multiple clients, and I'm trying to find a secure way to notify their servers of certain sensitive changes to their data.
The issue is that the most secure method I found for this is OAuth, but since my server will be pushing the updates to them, that would mean that each client would have to implement an OAuth provider solely to authenticate my server, and it feels like a bit of an overkill.
My question is: Keeping in mind that not all clients will use HTTPS, would it be enough to simply use a shared secret, a timestamp, and some form of encryption for their servers to safely receive and validate my updates or will that leave them vulnerable to attacks?
Yes, that would be secure. For simple messages I think JTW would be a very good choice. You could use it for just authentication or the actual notification itself. A few reasons you might want to use it:
It's signed, so you know the message hasn't been tampered with.
You can encrypt with public/private key pairs.
You can add any data you like.
It's very simple to implement and doesn't require back-and forth exchange between servers like OAuth often does.

How to restrict API endpoint access to certain clients?

I'm building an API using the Django Rest Framework.
I've looked at a whole bunch of documentation, however I can't seem to answer this:
How can I restrict my API such that only my iOS client can register users / log them in?
I understand that I can use OAuth2 or Token Authentication for additional endpoints. But for unauthenticated requests, is there any way of restricting them?
There's no truly secure way to guarantee requests are coming from a specific device. Checking headers seems like the best way, as mentioned by #dukebody, but should be considered as a "good enough" solution for most users.
I'd also question why you want to do this. APIs generally shouldn't be restricted to certain devices because it makes them less extensible. Moreover, REST/HTTP services should return the same result regardless of the client device; otherwise, you will cause headaches when dealing with caches and proxies between clients and your service.
If you are trying to format content specifically for iOS, you'd be better off adding a specific parameter like ?format=ios without checking headers, then just make sure your iOS client uses that param. That would be more in the spirit of REST and make things easier to cache as well as test.
I also encounter this issue.I would like to provide some of my thought.
My team would need to support some APIs with heavy operation and it would be open to unauthenticated users which is design by business logic.
That's why we need to restrict api requests to our app clients.
The API call is stateless and irrelative with caching and proxies.
In the other hand, some malicious attack like CSRF, you should also provide some additional protection on you API to prevent request sending from untrusted way.
There are several mechanism we considered.
Using HTTP header
This is untrusted and very easy to crack.
Use one static random generated API Key
Very common and easy-implementation way. Server generated one static random string as key and client must carry when sending request.
If you have to support web, this would be leak by web console.But if you only support app client and restrict your API connection with HTTPs. This should be safe enough.
Dynamic change API key with AES crypto algorithm
To prevent MITM or static API key is leak, I proposed to use AES crypto algorithm and encrypt current timestamp.
When server receive, decrypt and check whether the request is valid or not.
You can also append some string as salt to make the mechanism harder to brute force attack.
You can do as much effort to make it harder to crack, but it would never be absolutely 100% safe.
Hackers can still reverse engineer your app to see how the encryption works.
All you can do is making it harder.
This is my propose and hope it could inspire you.
If you have any other better solutions or find some bug in my proposal, please let me know.
Restrict the views to the user agent of the iOS client, checking the headers. See https://stackoverflow.com/a/4617648/356729