8

Background:

Currently in the process of building out a REST API, using node w/express and it is consumed by a mobile app and eventually a (modern browser based) website.

I'm trying to identify the best way to authorize a user's update/action request so they are only allowed to modify their own resources. The actions will occur at a semi high rate hence the concern.

Note: Ownership of entities can not be transferred in this use case.

Potential Solutions:

Solution: Store and maintain a list of each user's resources in a server session backed by something like reddis.

Concern(s): Persisting a server side session has its own set of complexities specifically scaling with multiple servers. This also violates the REST. do-sessions-really-violate-restfulness for more information.

Solution: Do a read query before the user's update/action query. IE give me this user's items then if its in the list proceed with update.

Concern(s): Overhead of an additional read every time a user acts on behalf of a resource.

Solution: Pass the user id down to the db layer and make it part of the update conditional or if you want to get fancy use something like Postgres' row level security for that resource depending on the data backend.

Concern(s): This seems a bit late in the request life cycle to check if the resource is the requesting user's. The error would have to be thrown all the way up from the data backend. On the same note it would also be a bit out of place considering the authentication and role based authorization is often done at the beginning of the request life cycle. The implementation is also dependent on the data backend. It also shoves business logic in the data backend.

Solution: Client side signed session of sorts. Either with a JWT or a encrypted/signed cookie. Essentially maintaining a trusted session containing a list of the user's resource ids.

Concern(s): The size of the client side session. The fact that it would be sent with every single request even when its not needed. Maintenance becomes extremely complex when you introduce the possibility of multiple active sessions/clients. How would you update the client side state when a resource was added on another client.

Solution: Pass a signed update token(JWT) or url to the client with the resource when the resource is fetched. Expect that when a resource is updated/actioned. The signed token would contain the user id and the resource id and you could verify easily against those.

Concern(s): Gets complex if resource ownership is transferable but in my case that is not a concern. Introduces complexity over a read before update. It's a bit odd?

Final Thoughts:

I'm leaning towards the last solution, but because I don't see it happen very often I'm wondering if I am missing something? or maybe its part of a design pattern I don't know about.

  • 1
    Assuming that it is possible for ownership to be transferred, the last approach would entail having to check if that user is still the owner of said resource. So you end up having the token plus one of the other approaches. – Miguel van de Laar Mar 29 '16 at 18:32
  • @MiguelvandeLaar Thanks for the response! you are correct, however in my use case ownership cannot be transferred, under any circumstances. – Ashtonian Mar 29 '16 at 18:44
  • 2
    "a server session" Unless I'm missing something substantial, REST precludes server-side sessions. – Lightness Races in Orbit Mar 29 '16 at 18:45
  • @BarryTheHatchet - It seems like that is debate-able, there is some interesting discussion here on that: stackoverflow.com/questions/6068113/…. That solution is also around last as it makes introducing new load balanced servers fun.. – Ashtonian Mar 29 '16 at 18:53
  • @Ashtonian: The 131-scored accepted answer to that question agrees with me ;) (as does the 223-scored followup) – Lightness Races in Orbit Mar 29 '16 at 18:54
1

I think there are two solutions in your list that fit your use case best; the read query before the update (solution 2) and sending an update token with the read request (solution 5).

If you're worried about performance, I'd decide on one or the other depending on how many reads vs updates to a resource you expect. If you expect way more updates than reads, then obviously solution 5 is better, because you don't need to do an additional database fetch to figure out the owner of the resource.

However, you shouldn't forget the security implications of giving out an update token. With solution 2, assuming authentication is secure, then updating a resource is probably also secure because you determine the owner of a resource on the server.

With solution 5, You don't double-check the claim the client makes, except that you check for a valid signature. If you're letting the update happen over a cleartext link (eg, no SSL), then only encoding the resource and user id in the token isn't secure. For one, you're opening yourself to replay attacks, so you should include a nonce that grows with each request. Also, if you don't encode a timestamp/expiration date in the update token, you basically give indefinite update access to anyone who has that token. Finally, if you don't want the nonce, then you should at least include an hmac of the fetched resource, so that the update token is only valid for the state of the resource as it was fetched. This makes replay attacks more difficult and further limits the damage knowledge of the update token can do, since the update token is only valid when the resource is in the given state.

I think that even if you're communicating over a secure link, adding a nonce (or at least an hmac of the state of the resource) and an expiration date for the update token would be a clever thing to do. I don't know the application domain, but you may deal with malicious users and they might wreck all kinds of havoc with the power of unlimited update access to their own resources.

Adding a nonce will mean an additional column per resource in your database where you store the value of the nonce you sent with the last fetch request. You can compute the hmac over the serialized json representation of your resource. You can then send your token not as part of the message body but as an additional HTTP header.

Oh, and I'd use a token, not a URL; in REST, the update URL for a given resource should be the same URL the resource was fetched from, right? I'd move all authentication & authorization-related stuff to the HTTP headers, e.g. you could provide the update token in the Authorization Header of the PUT request.

Note that adding a nonce that grows with each resource fetch will also require a database update (the new value for the nonce) for each resource fetch request (although you may get away with only updating the nonce when the state of the resource is actually changed, so it would be free from a performance standpoint), unless you want to keep that information in transient memory and simply have the clients retry when your server is restarted between a fetch and an update request.

A side note to your solution 4 (client side sessions): Depending on the number of resources your users can create, the session size might not be a problem. The client side session update problem might be fairly easy to solve, as well: If an update request to a resource fails because the resource is not listed in the session data you received from your client, but the user is correct, then you do a check in the backend whether the session data from that client is outdated. If it is, you allow the update and send back an updated cookie with the answer to the update request. This will only cause a database lookup when a user tries to update a resource from a client with outdated local session data (or when he is malicious and tries to ddos you, but rate limiting to the rescue!). However, I agree that solution 4 is more complicated than the others and you're better of with one of your other ideas. Solution 4 also has various security considerations you should take into account; storing this much authorization state on the client really needs your security to be watertight.

  • What if the all the resources that are owned by the user is modeled as child resources. (E.g /users/1/entity/2). Combine that with a signed JWT that has the user id. If you do this the authorization can even be delegated to a seperate server (API Gateway) because it does not need access to the database. – Chamindu Jul 8 '16 at 4:39
0

Another solution you may consider:

If a resource really can't be transferred to another user once it's created, you could think about encoding the user id in the resource id.

E.g. all resources belonging to user 'alice' are named 'alice-1', 'alice-2' etc.

It's then trivial to check whether 'eve' has access to a resource named 'alice-1'.

If you don't want the resource ownership to be public knowledge, you can use a cryptographic hash function like so:

  1. Given a password only your server knows
  2. And a username u (e.g. 'alice')
  3. And a resource name r (e.g. '1')

Generate hmac(password, u | '-' | r ), where | is concatenation. Use the result, along with the resource name r, as the id of the resource. Optionally add a salt value (like for storing passwords).

When an update request comes from user 'alice' for a given resource id, you extract r from the resource id, calculate hmac(password, 'alice' | '-' | r) and compare it to the remaining part of the resource id. If it matches, alice is allowed to update the resource, if it doesn't match, she's not authorized. And without the password, nobody can figure out who owns which resource.

I think that's secure, but you might want to brush up on the qualities of hmacs.

0

There seem to be two separate issues that you need to manage. They are (1) How are you authenticating the user who is generating the request? and (2) how do you know which back end objects are associated with that user. I also have an observation that may be suitable for your use case (3)

(1) User authentication in a RESTful way is never pretty. I tend to prefer using the HTTP Authentication / Authorisation headers and HTTP 401 responses to trigger authentication, which means that you are potentially authenticating the user on every request. As it is a mobile application, you do have the option of creating your own custom authentication scheme, which could allow you to supply a session token rather than full authentication details in future requests.

(2) The user associated with a set of objects is surely key data that you need to store along with the actual objects in your data store. As part of your business logic, it needs to check who is the owner of the object and compare it to the identity accessing the object. I would do this explicitly in code, as part of the business layer validating the request. If database hits are a big enough issue, than it would make sense to cache this information in a key value store, such as memcache or (for very high volume, highly available sites, riak) and only hit the database if the cache is cold for this user/object combination.

(3) If you have a small enough number of users and objects, you could combine the user and object id into the same field, and use this field as the database primary key for the objects table. e.g. 64bit number gives 24 bits space for the user ID and 40 bits of space for object ids. That way, when you are querying for the object you can be 100% sure it is for your user.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.