We are trying to develop an API for our service and we are doubting in how to accomplish the authentication process. Our clients have to be able to include a .js file which connects with our Node.js server. The key point here is that our backend must track the use of the API so our clients are going to be charged according to its use.
Our intention is to design the API as simple as possible for the users, as well as making it secure. We have thought of:
Creating an API_KEY for each user and matching it with their domains in every request. Problem here could be that the domain is not the most secure option, isn't it? We understand that the domain may be supplanted in an HTTP request.
Using a SDK with an API_KEY and SECRET_KEY to generate a token for a given session and user. I don't dislike at all this option but we would prefer a simpler solution for the developers, which would not imply using several APIs.
Do you have any ideas/suggestion/considerations/whatever?
Thanks in advance.
I like your second option best. In addition to an API_KEY and SECRET_KEY you can do a number of other things.
First of all make sure all requests are done through HTTPs. It is the single most important security feature you can add... and its easy to do.
Second if you want to make things super secure send a timestamp from the client. This timestamp can be used to hash the SECRET_KEY providing you protection against someone recreating data.
Your client would send the following with every request:
1) timestamp - you would store this in your database and reject any new requests with a smaller number
2) API_KEY - essentially a userID
3) signature - this is a hash of the SECRET_KEY, timestamp, and API_KEY. (The hashing algorithm and order of parameters is generally unimportant. SHA1 is pretty decent) Your server can calculate this hash to validate that this client actually knows the SECRET_KEY. At no time should your client ever disclose the SECRET_KEY to anyone.
You can also look into the OAuth standard. I believe NodeJS and Javascript in general both have libraries for it.
NodeJS OAuth Provider
Related
Frontend is Vue and my backend is an express rest api that pulls data from mysql. I want to secure both the frontend (login form) and backend api, but without limiting use of the api to just my frontend. I may want to use this api for other projects in the future.
What I'm strugging with is understanding how to have a user log in on the frontend but also give them access to the api without preventing future access to the api from other projects. I know I could set a JWT, but recently there seems to be a lot of "DON'T USE JWT!" articles out there, and I can understand why they might think this. Using cookies and sessions doesn't seem practical either without needing to create a session/cookie for each frontend and backend. Then I thought maybe using cookie/sessions for frontend, and having the frontend be authenticated with an API key to the backend API. This might allow other web applications to access the api while protecting it from unauthorized access.
Apologies for the lack of knowledge and seemingly rambling. I've been stuck on this aspect of my project for a while now. I know it's due to my poverty of knowledge on the subject. Any resources and points in the right direction will be greatly appreciated.
There is nothing wrong with JWTs, though it can depend on the implementation. The simplest way of doing it is just signing the JSON string with a private key. A little more complicated is base64 encoding it, encrypting it and signing only after that with a different key. And ofc. you need to send it through SSL. You need to add expiration time to it. Probably bind it to IP, browser, language, location, etc. too. If you want to revoke it, then you need to maintain a very small global revoked JWT database and remove it after it expired. You can add a JWT verification cache too, which spares you checking the signature for every request and which can be local too. If you want to avoid accessing it from Javascript code and probably leak it with XHR, then add it to a httpOnly cookie, though if you do so, then you need a CSRF token too. So I think all of the security issues are solveable with JWT too.
We need stateless communication between the REST client and the REST service, so if your frontend has a server side REST client, which uses for example JWT or any other method with Auhorization header, then it is perfectly fine from statelessness constraint perspective to do server side sessions with your frontend. As of the constraint itself, statelessness is needed for massive services with countless users global scale where handling server side sessions is an issue on its own, so better to move the stuff to the clients. These are typically social media services, search engines, global webshops, etc. If you have a limited user number, then you probably don't need this feature. Though using server side sessions between REST client and service would violate the statelessness constraint, which means you would not have a REST service. I don't think this is an issue. I mean it would be still a service, just not a REST service, it would work, would not scale as well as a REST service, but if this is what you need and it is simpler for you to implement it securely, then go on.
You can use API keys if you have some sort of revoke mechanism for those too. And keep in mind that API keys are server side stuff, so for mobile clients and in-browser application they are not good for identification, because they can be easily stolen by the users, so don't access your service directly from those with API keys just through a server. Another way is checking IP and using SSL to identify the clients, which is similar to using API keys, just more standard and the secret does not go through the communication channel. It really depends on your needs. If you have 3rd party clients, then you'll need OAuth too and let the users decide if they trust them.
Not sure if this helps.
By far the best thing you can do is adopt OAuth2. It has all the necessary components solve your problem and has ton of implementations.
The issue with JWT is that lots of people get it wrong. inf3rno does a good job accidentally pointing out many of the issues.
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
i need some advice.
i want to build a JS app that will run on a client browser and communicate with ajax with my server.
the problem is that i want to give this client some api-key so i can authorize it on my server.
security wise its a problem because as long that this key is sending through the ajax call, anyone can replicate this call.
i don't want to ask the client to create some proxy server and "curl" the request.
i want it to be directly from the client to my server.
what is the best practice for that except verifying the client by his IP or domain?
You could use something like a JWT.
You create an authentication object
{
apiKey: asd-dfgdf-e3234, // not even necessary (read on)
expires: 12213493434,
ip: "x.x.x.x"
}
You base64 encode it and then sign it with a private key (or hash function on your server) and attach the signature as a base64 string to the "payload".
eyBhcGk6IDEyMzQ1LTU2Nzc4LCBhcGk6IDEyNy4wLjAuMSB9.Tm90IFNlY3VyZSE=
| -------- payload ----------------------------| -- signature -|
Pass this to your client. Every request sends this token. It can be examined and verified to be tamper free (match the requesting IP no key necessary).
Sadly, you can only check the Referer header, and issue API keys with a whitelist of allowed referers.
The main issue here is Referer isn't secure at all: it can be changed. That is, anyone can impersonate a client...
AFAIK, the point is your clients should be able to re-create their API keys, and they should do it once they've realized that someone is impersonating them. And they should keep re-re-re-creating until the bad guy stops impersonating them...
Make it as hard as possible...
One possible approach to make things harder to unwanted clients impersonating actual clients can be using access tokens with expiration.
Also, a good practice can be that one client can request a limited number of access tokens everyday. If these access tokens have a 24 hour expiration time, and there's a limit of 3 or 4 access tokens per API key and per day, if many bad guys try to impersonate one of your clients, well, only 3 will be able to do so.
You can also define a limit of an access token per day. This could make things even harder.
BTW, you can argue that anyone can steal the whole access token too. Well, this is the time to re-generate the API key and get a new one. Finally these bad guys will get tired of getting their access tokens invalidated...
Best solution
Actually, if your API needs to be secure and it's private as you've said in some of your comments on my own answer, there's no choice here: you need to go the server proxy way.
I would check node-oauth2-server to use OAuth2 to secure your API.
I could do with some help on my REST API. I'm writing a Node.js app which is using Express, MongoDB and has Backbone.js on the client side. I've spent the last two days trying to work out all of this and not having much luck. I've already checked out:
Securing a REST API
Securing my REST API with OAuth while still allowing authentication via third party OAuth providers (using DotNetOpenAuth)
http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
http://tesoriere.com/2011/10/10/node.js-getting-oauth-up-and-working-using-express.js-and-railway.js/
I want to keep my backend and frontend as separate as possible so I thought about using a carefully designed REST API would be good. My thinking is that if I ever get round to developing an iPhone app (or something else like that), it could use the API to access data.
BUT, I want this to be secure. A user has logged into my web app and I want to ensure my API is secure. I read about OAuth, OAuth 2.0, OpenID, Hmac, hashes etc... I want to avoid using external logging in (Facebook/Twitter/etc) I want the registering and logging in to be on my app/server.
...but I'm still confused here. Maybe it's late at night or my brain is just fried, but I could really do with some steps on what to do here. What are the steps for me to create a secure API?
Any help, any information, any examples, steps or anything would be great. Please help!
In order of increasing security / complexity:
Basic HTTP Auth
Many API libraries will let you build this in (Piston in Django for example) or you can let your webserver handle it. Both Nginx and Apache can use server directives to secure a site with a simple b64encoded password. It's not the most secure thing in the world but it is at least a username and password!
If you're using Nginx you can add a section to your host config like so:
auth_basic "Restricted";
auth_basic_user_file /path/to/htpasswd;
(Put it in your location / block)
Docs: http://wiki.nginx.org/HttpAuthBasicModule
You'll need to get the python script to generate that password and put the output into a file: http://trac.edgewall.org/browser/trunk/contrib/htpasswd.py?format=txt
The location of the file doesn't matter too much as long as Nginx has access to it.
HTTPS
Secure the connection from your server to the app, this is the most basic and will prevent man in the middle attacks.
You can do this with Nginx, the docs for it are very comprehensive: http://wiki.nginx.org/HttpSslModule
A self-signed certificate for this would be fine (and free!).
API Keys
These could be in any format you like but they give you the benefit of revoking access should you need to. Possibly not the perfect solution for you if you're developing both ends of the connection. They tend to be used when you have third parties using the API, eg Github.
OAuth
OAuth 2.0 is the one to go with here. While I don't know the underlying workings of the spec it's the defacto standard for most authentication now (Twitter, Facebook, Google, etc.) and there are a ton of libraries and docs to help you get those implemented. That being said, it's usually used to authenticate a user by asking a third party service for the authentication.
Given that you doing the development both ends it would probably be enough to put your API behind Basic HTTP Auth and serve it over HTTPS, especially if you don't want to waste time messing around with OAuth.
Here's a different way of thinking about it:
Let's suppose for a moment that you're not using an API. Your user logs into the app, providing some credentials, and you give a cookie or similar token of some sort to the user, which you use to identify that user has logged in. The user then requests a page containing restricted information (or creating/modifying/deleting it), so you check that this token to ensure that the user is allowed to view that information.
Now, it sounds to me that the only thing you're changing here is the way that information is delivered. Instead of delivering the information as rendered HTML, you're returning the information as JSON and rendering it on the client side. Your AJAX requests to the server will carry that same logged-in token as before, so I suggest just checking that token, and restricting the information down to 'just what the user is allowed to know' in the same way.
Your API is now as secure as your login is - if anyone was to know the token necessary for accessing the api, they would also be logged into the site and have access to all the information anyway. Best bit is, if you've already implemented login, you've not really had to do any more work.
The point of systems such as OAuth is to provide this 'logging in' method, usually from a third party application and as a developer. This would potentially be a good solution for an iPhone app or similar, but that's in the future. Nothing wrong with the API accepting more than one authentication method!
The answers so far do a great job of explaining, but don't give any actual steps. I came across this blog post that goes into great detail about how to create and manage tokens securely with Node + Passport.
http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/
Tips valid for securing any web application
If you want to secure your application, then you should definitely start by using HTTPS instead of HTTP, this ensures a creating secure channel between you & the users that will prevent sniffing the data sent back & forth to the users & will help keep the data exchanged confidential.
You can use JWTs (JSON Web Tokens) to secure RESTful APIs, this has many benefits when compared to the server-side sessions, the benefits are mainly:
1- More scalable, as your API servers will not have to maintain sessions for each user (which can be a big burden when you have many sessions)
2- JWTs are self contained & have the claims which define the user role for example & what he can access & issued at date & expiry date (after which JWT won't be valid)
3- Easier to handle across load-balancers & if you have multiple API servers as you won't have to share session data nor configure server to route the session to same server, whenever a request with a JWT hit any server it can be authenticated & authorized
4- Less pressure on your DB as well as you won't have to constantly store & retrieve session id & data for each request
5- The JWTs can't be tampered with if you use a strong key to sign the JWT, so you can trust the claims in the JWT that is sent with the request without having to check the user session & whether he is authorized or not, you can just check the JWT & then you are all set to know who & what this user can do.
Node.js specific libraries to implement JWTs:
Many libraries provide easy ways to create & validate JWTs, for example: in node.js one of the most popular is jsonwebtoken, also for validating the JWTs you can use the same library or use express-jwt or koa-jwt (if you are using express/koa)
Since REST APIs generally aims to keep the server stateless, so JWTs are more compatible with that concept as each request is sent with Authorization token that is self contained (JWT) without the server having to keep track of user session compared to sessions which make the server stateful so that it remembers the user & his role, however, sessions are also widely used & have their pros, which you can search for if you want.
One important thing to note is that you have to securely deliver the JWT to the client using HTTPS & save it in a secure place (for example in local storage).
You can learn more about JWTs from this link
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)