We have had some issues when it comes to access control. We have a profile object that maps to a users appfarm user. Within this object there are several attributes as firstname, lastname etc. We want some of the attributes to be changed by the user themself using the UI, and other attributes to only be changed by an admin in graphql. With some “hacking”, we were able to change other profiles and attributes to our own profile without the use of UI (using tools as Burp to send requests to an endpoint). Is there any solutions for this?
I’m not quite sure if I understand what the problem is - is the issue regarding changing/updating object class properties of the “Profile” object class, or the built-in appfarm “User” object class?
Changes to User object class (phone, firstname, lastname, roles) is only possible through the Update User Account action node (which may be included in functionality for admins updating other user accounts, or for users updating themselves). Note that the Roles that should be allowed to Update User, must be given explicit priviliges in Appfarm Create (Permissions → Account and Roles).
If you have a Profile object class, with a property Profile.User referring the User object class, you may
have firstname, lastname and phone as properties of the Profile object class as well, but shouldn’t need that if all Profiles also have a User object. If you use GraphQL, a user with a Role with permissions to update Profiles, will have access to update ALL profiles.
Maybe this latter point is that you refer to as broken access control? The concept for mitigating this is under development, and is called filtered security: With this new feature, you may set conditions on the permissions, meaning that a normal user member of role “Normal User” may be allowed to update the “Profile”, but only is that Profile belongs to your own User. But the solution for this per now, if to put such important updates in a Service, with an IF statement (if Profile.User = Current User) prior to the update, and not do this through GraphQL.
Hi @Erlend, filtered security is on our roadmap and we appreciate the importance of getting this in place.
At the moment the only known workaround requires the use of Run service action node where the service account you run it as has permission to update objects, while your regular users can only read them. The setup is not exactly straightforward, unfortunately.
In the meantime it’s worth evaluating the risk of 1) users having your ‘hacking’ skills, 2) users having the intention of malicious data modification, 3) the data actually being modified (= what kind of information do we store, is it sensitive, is it necessary to store it, etc.).
We’ll keep you posted when we have some details regarding the timeline.
Do you have any examples of you this can be done? I am not sure if I understood how I can set up a service for this. Will this service have any negative effect on the application?
We’ll look into setting up a showroom example, I’ll keep you posted.
The solution is pretty complex and requires building an API that you’d use internally. For absolutely crucial elements of a system, it can be done, but if you have the option to wait it out, it might be worth it in terms of the time spent and scalability of this workaround.
Is there any indication of an ETA on the filtered security? Just worried, because it’s really not relevant to evaluate the risk of users having hacking skills or bad intentions when “anyone” within an Appfarm app where you can, e.g., edit your own personal information in an extra profile or user object, can access and edit everyone else’s as well (excluding the ones using the “quick fix” described as pretty complex requiring internally built API).
The described workaround addresses server-side security. In addition to this you can of course use client-side rules to make sure that even though an operation might technically be possible to perform on the server, an average user won’t be able to get this far.
The current ETA of filtered security is end of Q2 for internal beta and selected customers.
Filtered security will be the best solution for problems like this, but it is possible to use workarounds to achieve the same functionality today.
For this specific case, I would do the following:
The app should read the profile object for the current user into a runtime data source, and there should be no persist actions defined that point to this data source. As long as the app uses this pattern to access the profile, there is no way to change the profile object through the app’s API, even when faking messages through a proxy. The pathways to change that object is not created.
Define a service endpoint responsible for updating the user profile. This endpoint must have logic that only allows changing the current user’s profile object. This service should then be invoked from the app using the run service when the user wants to change its profile. Don’t send the user id as a parameter; use the service’s current user data source to determine who the user is.
GraphQL must not be enabled on the profile object class since it currently can be invoked using the same authentication cookie as the app is using. The admin interface should be defined in a service endpoint instead and have similar logic as the one used for editing the user’s own profile.
I acknowledge that this pattern is not ideal and doesn’t scale from a maintainability perspective, but it can be used to protect sensitive data.
We also have other security-related features in the pipeline like:
Scoping of how GraphQL and Services can be accessed
Possibility to define custom properties on the user object
Possibility to determine who the original user is when calling a service with elevated privileges (by using run service as).
This profile example is only an example in a larger application. The main problem is that any App users would be able to change attributes in objects they have access to, so I don’t know how scalable the first solution provided would be.
If a service is set up for changing objects in the application, would this be a massive hit for the performance of the app?
The answer is that “it depends”. It is possible to speed up an application by offloading workloads to a service, and it is possible to slow it down by implementing it “wrong”.
Using services to update some properties can be very performant, and the user will probably not notice anything.
Hi! We now tried to set up services for protecting user data. Following our previous discussion, we’ve configured a service account to execute a service when a user attempts to modify their profile. The endpoint is designed to only permit changes to the profile of the current user. However, we’ve encountered an issue where the current user data is undefined when the service is invoked using the service account. Do you have any suggestions for what we should do, or if there might be any misunderstandings regarding our instructions?
Hi! Are you using the “Run as service account” when you have set up the “Run Service” action node from the App? You should not use that option in this case. So, the user (using the App) should be member of a role with access to the Service. Inside the Service, you should then be able to use “Current User” (being the actual user triggering the service endpoint) to read the Profile-object from the database and update it.