What does an ACL for a REST service need? - rest

I have a REST service with authentication. So I can prevent clients which aren't authenticated from doing specific things.
But how to do the access control for a community-like service?
I mean, there is stuff like
you can edit your profile
just your friends can download it
just admins can delete your profile
moderators can delete posts
etc.
Which seems like different problems to me
I got something like roles: admin, moderator, user
I got something like "friends": a dynamic list of users
I can do a match on the route for every request. since it's a REST service the route defines how what gets done. So I could intercept every route and check it for permissions, which would keep the permission checking from the controllers.
But how to store it? Attaching it to every piece of information in the DB or building and maintaining a separate datastructure? if the last one, how to structure it?

Related

What is the best approach to stop your platform's users to "sniff" the frontend requests to backend and modify them?

So I have a platform that works like this: Users can create accounts by logging in with their Google (I USE AUTH0) and then they can create "Projects" which contain lots of other unimportant stuff regarding my current problem (like todo lists, ability to upload files etc; they can also Edit the project by changing some of it's attributes like name, description, theme and so on). There is a home page where everyone can see each other's projects and access them (but not upload files, change the tasks in the to do lists; this is possible only by the person that owns it).
By using a tool like Burp, people can see the request made from frontend to backend, for example when accessing one of the projects, and modify it on the fly.
This is what it looks like inside Burp when they access one of the projects:
As you can see there is a Get request to /projects/idOfTheProject; they can replace the GET with DELETE for example and they will successfully delete it; they can also see what is sent to the backend when a project is edited (name changed, description, thumbnail picture etc) and change anything they want about it.
How should I prevent this?
What I've looked at so far:
a. JWT - Probably the best fitting for my situation, but required the most work to be done (as I already have my platform almost finished with no such a security measure implemented yet, so I may need to rewrite a lot of things in both backend and frontend)
b. Sending the user's id that initiated the action as well to the backend and verify if it has the necessary privileges - the worst solution as users can access each other's profile and see the id, then just change another field in the request's JSON
c. Have a sort of token for each user and send that instead of the user's id - in this way somebody can't get your token by just looking at the communication between frontend and backend (only if it is using YOUR account). That token should be taken maybe somewhere from the auth0 when they create their account? If they provide something like that; or I can just create it myself and store it alongside the other user variables. You would still see the requests in plain text but even if you modified something you would still have to "guess" the owner's token, which will be impossible.
For frontend I use NextJS and for backend Flask.
Thank you in advance!
The TL;DR is that you don’t. A determined user will always be able to see what requests are being sent out by the code running on their computer and over their network. What you are describing when asking how to prevent people from “sniffing” these requests is security through obscurity, which isn’t actually secure at all.
What you should do instead is have an authorization system on your backend which will check if the current user can perform a given action on a given resource. For example, verifying that a user is an administrator before allowing them to delete a blog post, or making sure that the current user is on the same account as another user before allowing the current user to see details about the other user.

REST API Resource Naming Conventions - User or Users (pluralisation)

Long Version
For some, myself included, one of the most painful and headache causing parts of building a REST API is determining the name for each resource and the accompanying endpoints.
Whilst it is, of course, down to personal preference; there are certain things that are encouraged by the community. For example, most people, including me, will pluralise their resource names:
GET /notifications
POST /posts
However, there are cases where pluralising just doesn't seem correct. Consider the following example where user essentially represents the logged in user, not the entire users resource:
Endpoints only relevant to the authenticated user
// Phone Verification
POST /user/phone/request
POST /user/phone/resend
POST /user/phone/verify
// User creation based on authenticated and verified phone
POST /user
// Update authenticated user's profile
PUT /user
// Delete the authenticated user
DELETE /user
// Add/remove the authenticated user's profile image
POST /user/image
DELETE /user/image
// Update the authenticated user's device token
PUT /device/token
Endpoints that access the entire users resource
GET /user
GET /user/{id|self}
In the above example, to me, it feels like the singular user resource name is more suited given on the majority of the endpoints, user refers to the authenticated user, not the entire database of users. But, on the other hand, having GET /user return all users just seems plain wrong...
As a result, I am now torn between user and users - both have strong arguments either way as I see it but would very much welcome another person's opinion on the matter...
Short Version
TLDR - To put it simply, consider the following two endpoints:
// Get all users
GET /users
// Update the authenticated user's device token
PUT /user/device
Both of the above seem correct in my eyes. The problem with the above is that there is no way I am going to have both user and users, it has to be one or the other in my opinion.
The dilemma; Why would I use user when the resource refers to the entire users database? Why would I use users when the resource only refers to the authenticated user?
I cannot get my head around this one... Anyone got any thoughts on this? Or, even better, an alternative solution to my proposed endpoint structure?
Update
After some deep thinking, I have come up with an alternative solution to this but I am still not 100% sure on it as I am not overly keen on using the auth resource name.
Consider this:
// auth = authenticated user
// users = users collection
POST /auth/request
POST /auth/resend
POST /auth/verify
POST /auth
PUT /auth
DELETE /auth
POST /auth/image
DELETE /auth/image
PUT /auth/device/token
GET /users
GET /users/{id}
There are obviously different opinions on this matter, the answer below contains my personal views.
The bottom line is that it's all quite subjective and depends on the way one looks at a certain (type of) resource.
Why would I use user when the resource refers to the entire users
database?
In my opinion, you should never use singular for an endpoint that contains multiple resources.
Some people, however, argue that we should stick to singulars for all resources, mostly for the sake of simplicity and uniformity.
Why would I use users when the resource only refers to the
authenticated user?
You will find quite some different opinions on this, but the consensus and most widely adopted is generally to stick with plurals, except for resources that can only contain a single item (for example, a user profile only containing only one avatar).
Also, since using a singular form for the users resource wouldn't make sense following the above logic, we don't want to mix singular and plural names.
// Update the authenticated user's device token
PUT /user/device
You can interpret 'updating the authenticated user's device token' as follows:
Add a device token to a user entity of the users resource collection.
If your API supports view devices' data of other users, the API can be like /users/$user_id/devices
whereas, when you always have to get the current logged-in user's devices information, the API can simply be /devices (as current user is implied).
i.e IMO, wherever you have only 1 parent resource accessible (say in this case current user is always singular), you can skip that resource in the API URL.

REST Endpoints for Current User vs ID

As far as REST APIs go, which is the better structure to follow in general?
Assume GET/PUT/POST/DELETE for all resources.
1) Use currently signed in user for /users/**/* routes.
/users
/users/password
/users/email
/users/preferences
/users/documents
/documents/:id
2) Having absolute paths with IDs and using /users/:id for currently signed in user?
/users
/users/:id/password
/users/:id/email
/users/:id/preferences
/preferences/:id
Does it matter?
If the resource you are referring can be multiple, you should go with
/resource/resource_id
In the above case, user can only be the current person, so using a pattern like /users/user_id, sounds odd. Because, you will have to handle different cases like What if a logged in USER A triggers an api call with a different user-id USER B??
You can have a namespace like /profile for managing the email, name, image etc. You don't have to make it as /users/profile as it is implicit that the data is going to be manipulated / accessed for the current logged in user.
Both are fine. What's nice about creating unique endpoints for every user, is that one day you can allow user X to access information about user Y.
The pattern I followed in a recent API was to create a unique endpoint for every user, but 1 endpoint /current-user that redirects to the /user/:some-id.
A url might indicate an identity. It makes a lot of sense that other resources might refer to user as a 'creator' or 'modifier' of sommething, and in those places you might want to use a url (and not just a userId).

REST API: Design routes based on roles

I'm currently creating a CRUD for Users on my system, there are two kinds of users (Parent users and child users).
A parent user can get/update/delete the permissions of his childs so i was thinking to create the following endpoints on my API:
GET /parents/{parentId}/childs/{childId}/permissions
PUT /parents/{parentId}/childs/{childId}/permissions
DELETE /parents/{parentId}/childs/{childId}/permissions/{permissionId}
But there is a third type of user (Admin) that can get/update/remove the permissions of any user he wants, so i was thinking on creating another set of endpoints:
GET /users/{userId}/permissions
PUT /users/{userId}/permissions
DELETE /users/{userId}/permissions/{permissionId}
Now the problem with this approach is that i would end with a lot of endpoints that do the same, so my question is: there is a best practice for rest endpoints when there are different roles or is it fine to have multiple endpoints that perform the same action?
I would probably organize it so that you only have the admin end points, and use a role to determine what actions are valid. For instance, if we're looking at permissions, the parent would issue /user/{userid}/permissions/{permissionId} where the userid and permission id corresponds to that of their child. If it is, the call executes and returns a 200. However, if they issue that command for someone who isn't their child, it returns an unauthorized.
For permissions, i would use a mechanism like a java web token that gets passed to the endpoint with every request.

Can you prevent a user logging in multiple times with Janrain, or similar social network logins?

I would like to enable logging in from multiple services on my site, but would not like users to login with, say, facebook and then logout and then back in with, say, Google+.
I am not sure if there is a practical way to detect that someone has done this?
I saw Janrain mentions account linking, is this provide this kind of service?
Security doesn't have to be watertight, but would like to make it hard to login multiple times and post from different accounts. At the same time, having multiple providers would be desirable to as not everyone uses Facebook.
Thanks for any help/info/suggestions.
Unfortunately there is no one point where you can check if a give account on one service is the same person as an account on another service.
One way is to drop a cookie on their browser when they log in with Service A, this cookie would indicate te service the user used to log in the last time. Then the next time they arrive on your site you can check for your cookie and then only show the login service they previously used.
Another option to make it more difficult to log in from multiple services is to request the email address of the user from the service and see if it already exists in your Database under a different account?