13
votes

After creating a basic REST service, I've have come to the point where it would be appropriate to add some sort of password protection, as I need to verify that my users are both properly logged and have sufficient permissions to execute whatever action they are going to.

The REST service will mainly be accessed from a Javascript-heavy frontend and with that in mind, I have come up with the two following alternatives to solve this:

  1. Make users login by first sending credentials to a /login page with POST. The page sets a session cookie wherein the user is marked as logged in, along with the permission level. On each following request, I verify that the user is logged in and his/her permission level. When the session expires, automatically or manually (logout, the user will have to re-logon).

  2. Temporarily save the credentials hashed locally and send the users credentials along every single request made by the user to verify the credentials & permissions backend on a per-request basis.

Are there more ways to solve this and is there something else that I should be concerned with?

5
If your backend is in Java you could also use Apache Shiro, it will nicely solve most of your problem.pierpytom

5 Answers

19
votes

I'm currently developing a REST API along with a client (written in javascript), below I'll try to explain the methods used to protect the API against unauthorized access.

  • Make your REST API to require a Auth-Key header upon every request to the API, besides /api/authenticate.

  • /api/authenticate will take a username and a password (sent using POST), and return user information along side with the Auth-Key.

  • This Auth-Key is randomly generated after a call to /api/authenticate and stored in the backend users table with the specific user entry, a md5 hash of the remote ip + the user agent provided by the client.

  • On every request the value of Auth-Key, and the md5 sum mentioned, is searched for in users . If a valid user is found that has been active during the past N minutes the user will be granted access, if not: http return code 401.

  • In the REST client, first get the Auth-Key by posting to /api/authenticate, then store this value in a variable and send in on every future request.

3
votes

If you want to stay true to the definition of a REST service then it should be stateless and not store any login (or other context specific) data on the server: http://en.wikipedia.org/wiki/Representational_state_transfer#Constraints

Your 2nd approach would fit this model

2
votes

First decide what it is that you're protecting against:

  • Authentication? (Knowing who is requesting your service?)
  • Authorization? (Whether a given person can properly request a given service or not?)

I recommend that you provide hashed keys for your service. That way you can manage the key issue separately from the services. Or a client key and a secret, Amazon does this.

It is always easier for the client if you have a stateless protocol. And send everything through the parameters, cookies are a bother for the client too.

Remember that it is in your interest to make it as easy as possible for potential developers to use your service. A super secure service that no one uses is boring.

You can let clients choose the security level by giving them the choice of HTTP or SSL/HTTP endpoints to connect to. Client choice is a good thing.

1
votes
  1. Make users login by first sending credentials to a /login page with POST. The page sets a session cookie wherein the user is marked as logged in, along with the permission level. On each following request, I verify that the user is logged in and his/her permission level. When the session expires, automatically or manually (logout, the user will have to re-logon).

  2. Temporarily save the credentials hashed locally and send the users credentials along every single request made by the user to verify the credentials & permissions backend on a per-request basis.

Your first approach does not meat the statelessness constraint of REST. You cannot maintain client sessions on server side. This constraint makes REST highly scalable...

Your second solution is appropriate. The simplest way to use HTTP basic auth. You don't have to hash the password on client side. What you need is an encrypted connection. On server side you can have an [username, password] -> [identity, permissions] cache, so this solution is much faster and superior in every other way than having server side sessions.

By 3rd party (non-trusted) clients the authentication is more complex, I guess you don't need that part.

0
votes

I'm no security-expert. I use the RESTful Play!-webframework and they do the following things to authenticate users.

  1. The cookie is protected against manipulation. It is signed with a long secret key and is checked for each request. Just hashing it is not enough!
  2. They recommend to set unique information the identify the user in the cookie. As the server should be the only one to manipulate the cookie, that's enough.
  3. Don't put the password as credential in the cookie. If someone sniffs the cookie, not only the session can be hijacked, but also the complete account or even worse, other accounts with the same credentials.

If you want to protect the cookie against hijacking using https.