ChatGPT解决这个技术问题 Extra ChatGPT

Securing my Node.js app's REST 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!

What did you end up doing?

j
jturnbull

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.


Great answer. I see that OAuth seems to be the standard. But there seems to be 2-legged OAuth 1.0, 3-legged OAuth 1 and then this OAuth 2... So I should look into OAuth 2? ...I was thinking of HTTPS/SSL, but I'm not sure how something like an iPhone app could transmit over that (is that even possible)? ...another question with OAuth, can I be a provider as well as consumer, or do I need to - like you say - need to use a third-party to authenticate? In this situation, using a third-party wouldn't be too preferable, it's not really that sort of app. Thanks for the detailed reply!
OAuth 2 is the updated OAuth. I believe 1.0 is now considered "bad". iPhone will definitely work over HTTPS (Github in mobile Safari!).
You can be both but typically OAuth is used to authenticate using a third party. As @mjtamlyn pointed out below, using your current auth system is certainly a possibility. I've updated my answer with some steps for some of the parts.
Thank you for the answer! That's has given me lots of information to process as all of this auth stuff is very new to me :)
I just came across this article that briefly explains OAuth1 and OAuth2 stormpath.com/blog/secure-your-rest-api-right-way
m
mjtamlyn

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!


So am I just over-thinking it I presume? I already have 'normal' authentication going on... User logs in, cookie gets created for the session and the site checks to see if the user is logged in for the various 'secure' parts. So in essence, that's it!? ...I'm just over-thinking the problem and trying to deal with OAuth etc, but in reality, it's still just the basic auth stuff... Now, if that is what it is, then that is just fine! I suppose, if anything, I do need to get SSL sorted on my server, but apart from that, I can just use my normal auth procedure?
It could be that I'm missing something here, but doesn't this sort of violate the capital rule of API's? I.e.: no server-side state? If the server needs to keep track of tokens, then it means holding state, which should be a bit of a no-no :-)
@Dieter it's stateless in that the state is not being passed in the http
@dieter The tokens can be constructed so that the server(s) don't have to maintain a db of issued tokens in order to validate a token. Sign the token with a private key so that anyone with the matching public key can verify that a) the token was issued by a trusted server (authenticity) and b) the token has not been modified (fidelity). The token is the state data, so the server can be stateless. OAuth2 doesn't define the content of a token, just how to get one. JSON Web Tokens (JWT) define a secure token format that can be used with OAuth2.
@dthorpe Thanks! That makes sense. TypoJohnson, For the record, I'm pretty sure that's not what stateless means in API's. Stateless = the API can handle any request without having to remember anything. So that it doesn't matter if server 2 handles a client that was being served by server 1 a minute ago. So having state passed in the http (by the client) is actually quite alright in some cases. And if it's not possible, then they'll just have to share a DB or a cache between all the API servers
a
andyzinsser

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/


P
Pang

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