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.
Related
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.
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
I have developed an API for my new service and am in process of developing SDKs (php, ruby and JavaScript) for this API.
Some of the calls to API are open to public, but some require API key and API secret. My question is, how do I make sure that people can hide their key and secret from world while using JavaScript API.
I would Imagine the call something like:
jQuery.ajax({
url:'http://api.domain.com/v1/display/',
data: {offset:0, limit:0, apiKey:'apikeynotlikelogin',apiSecret:'apisecretlikepassword'},
success: function(data){
alert(data);
}
});
But almost everyone these days know that if they open firebug or even simplier ctrl+shift+j in chrome, they can see the code together with all information above. I have considered many options, but it seems to me like there is just no way how to hide apiKey and apiSecret on front-end.
Any suggestions? There must be a way Im sure.
Thanks!
EDIT:
Thanks everyone for answers and trying to solve the issue. Here are some of the answers and why is still not what I need:
Using domain name in the request to make sure its from the correct client.
This is valid suggestion, but still could be quite easily faked
Generating unique key for each call
This seems to be more advanced, but again I found it not usable for my case. I need to authorize the "App" (thats what people register in system in order to get credentials and authorize to API) because users will have different levels of privacy set and according to those clients will be served with result.
So If I cam make client to first call "handshake" to get the session unique key, but then again (either in handshake or next request), client has to send his apiKey and apiSecret in order to authorize to API and get the correct result (according to policies etc.) So at the end, it is exactly the same as without the handshake request, anyone who knows the apiKey and apiSecret could first call handshake and then the authorization.
Hope it makes sense
You can make it harder, but you can't really secure it.
You can have them register the pages from which they are going to make the requests, and check that the request originates from an authorized origin when checking authentication. Not perfect, as this can be faked, but harder for a casual user.
Or they can proxy through a server, but this does not help much since they need to secure access to their proxy.
I am using nodejs to write an image upload service. Paying clients will be able to send an image file to my endpoint that I have set up on my server. However, when every request comes in, I need to confirm that it is actually a paying client making the request. I thought about having the client give me their domain name and I would just check the referer header. However, someone could easily spoof the referer header and use my service without paying. How do SaaS developers face this technical problem? Is it possible to fix this without requiring my clients to have some server side code?
Are you building an external image hosting service for websites or is it to share something that HAS to be private and SECURE? If it is the former then read ahead.
Of course, the header can be spoofed. Here's why you should not worry about it:
Alternative is ugly: To build a secure provisioning service, you will have to develop some kind of token system that the website owner implements at his end as well. Chances are, he would not sign up with you because there are simpler alternatives available.
Spoofing will have to be done on client side. Very few "users" will actually do this. Two geeks spoofing headers on their own machine will not make a big difference to you. If they write some proxy or middle ware that does this work automatically and many people start using it, it could be a problem. However this is not very likely.
Guess you already know, but since you haven't mentioned - it is called Hotlinking. Google this topic to find more resources.
You cannot authenticate a browser with a referrer header.
If you want to authenticate an individual, then you will likely need a login system that they provide credentials to (username/pwd) and you check those against your allowed user base. If they pass, then you set a certain type of cookie in the browser that indicates they are a legit user. Subsequent requests from this user will contain that cookie which you can check on every request.
The cookie needs to be something that you create that you can verify that cannot easily be guessed or forged (like a session or an encrypted token from your server). You would typically set an expiration on the cookie after some time period of time so that the user has to login again.
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