v8-archive
v8-archive copied to clipboard
Users are able to elevate their own roles
Accidentally it turned out, that as a low-privileged user I am able to elevate my own role to admin.
- Directus 8.8.0 Installed with one-click installation on DigitalOcean droplet along with:
- Ubuntu 18.04
- Apache 2.4
- MySQL 5.7
- PHP 7.2
Steps to reproduce:
1. As an admin user, I create a new role (called "Test") with default permissions (as below)
2. I want active users of "Test" role to be able to modify their own user profiles in regards to first_name and last_name only:
Of course, "Test" users permissions in regards to updating user profiles are set to "mine".
However, I also don't want "Test" users to be able to modify any of given roles and permissions, so I'm disabling their access to related collections:
3. As permissions for the new role are set, I'm creating new "Test User" with role set to "Test"
4. Now I'm signing myself in as a newly created user and I'm trying to edit my own user profile:
For now everything looks like expected. I don't have permissions to edit my own role. I only have access to First Name and Last Name Fields (and, for some reason, for Timezone as well):
5. BUT, besides GUI, there is also a RESTful API, that I can use. So let's try to sign in through it (as a test user of course).
I'm now sending a POST request for
{ "data": { "token": "<token>", "user": { "id": "4", "status": "active", "role": "4", "first_name": "Test", "last_name": "User", "email": "[email protected]", "timezone": "Europe/Warsaw", "locale": "en-US", "locale_options": null, "avatar": null, "company": null, "title": null, "external_id": "<externalId>", "theme": "auto", "2fa_secret": null, "password_reset_token": null } }, "public": true }
Note that my role is set to 4 which is and id for my "Test" role.
6. Now let's take my token and try to elevate my role through API.
I'm now sending a PATCH request for [host]/[project]/users/4 along with the following payload:
{ "role": 1 }
Where 1 corresponds to built-in "Admin" role.
I'm attaching my token in querystring, so the complete request URL looks like this:
[host]/[project]/users/4?access_token=[access token taken from previous request]
Let's send this request to the server... * puff * and now let's take a look at the response:
{ "data": { "id": 4, "status": "active", "role": 1, "first_name": "Test", "last_name": "User", "email": "[email protected]", "token": "<token>", "timezone": "Europe/Warsaw", "locale": "en-US", "locale_options": null, "avatar": null, "company": null, "title": null, "email_notifications": true, "last_access_on": "2020-07-30 09:38:44", "last_page": "/zpruszkowa/users/4", "external_id": "<externalId>", "theme": "auto", "2fa_secret": null, "password_reset_token": null } }
As we can see, my new role is 1 which means, that I just elevated my permissions to Admin.
7. Now let's go back to the Directus GUI and...
Tadamm!
My test user is now an admin.
I'm pretty sure that this isn't supposed to work this way. I want my users to be able to change their own personal data (like e-mail address) but I am not sure if I want to grant them a privilige to change their own role to admin.
If you have acknowledged this bug, please, take into consideration also following related issue: -> as a an authenticated user with defaults permissions, I have access to all revisions and activities through API. After lowering level of permissions for Revisions and Activities application's GUI throws errors and eventually breaks. Granting access to all revisions means basically allowing access to all the data in the app.
It seems the API request may be bypassing the validation of the user-role interface if you set all the required permissions. Did you try clicking on the all button next to the status to turn on or off the fields?
By default when you grant permission, all fields are readable and writable for the status you select.
In the meantime, if that does not work, I would suggest a hook to look for the incoming data object and adjust using the following hooks: item.create:before
and item.update:before
.
It would be cool to have roles non-writable by default in future releases.
For revisions and activity, what were the permission settings? You don't want the API user to see revisions or just the delta and data fields?
We found the same revision bug as @kosicielPL. If a user has permission to read revisions, he will be able to inspect data from not only restricted collections, but also any system tables, such as users. You can then get access tokens and passwords set by administrators when creating new users.
Steps to reproduce from a clean installation:
- Create a new role
- Create a new user ("attacker"), assign him the previously created role
For the default admin user :
- Change any field of the admin user
- As the attacker user, access the revision history of the admin user http://localhost:8080/_/users/1/revisions
For any other user :
- Create the user, set a default password
- As the attacker user, access the revision history of the user http://localhost:8080/_/users/the_user_id/revisions
- The default password is accessible in the revision history
- Change any field of the user
- The user token is now available in the revision history
(For some reason, the token only appears in the revision history if a modification has been made to the user, even though the token is already generated)
@Jeremy-Gaillard in the meantime, you can prevent a non-trusted user from reading certain fields in the activity collection.
They can see the activity not just all of it. See image for permissions:
By setting the data and delta fields off, that user will see this:
"data": [
{
"id": 226,
"activity": 238,
"collection": "app_collections_configuration",
"item": "11",
"parent_collection": null,
"parent_item": null,
"parent_changed": false
},
{
"id": 227,
"activity": 239,
"collection": "app_collections_configuration",
"item": "12",
"parent_collection": null,
"parent_item": null,
"parent_changed": false
}
]
}
The permissions of Directus are very granular and will only improve in the next version(s).
@kosicielPL I was able to get the role blocked from updates by any user in a non-admin role.
You can accomplish that by setting granular permissions on the user collection as follows:
Then if you run this PATCH and try to update the role:
{{api}}/app/users/2?access_token={{access_token}}
You should get this response:
{
"error": {
"code": 305,
"message": "Write access to \"role\" field in \"directus_users\" collection was denied",
"class": "Directus\\Permissions\\Exception\\ForbiddenFieldWriteException",
"file": "/Users/philleepflorence/Sites/Directus/suite/src/core/Directus/Permissions/Acl.php",
"line": 1232
}
}
@Jeremy-Gaillard in the meantime, you can prevent a non-trusted user from reading certain fields in the activity collection.
They can see the activity not just all of it. See image for permissions:
By setting the data and delta fields off, that user will see this:
"data": [ { "id": 226, "activity": 238, "collection": "app_collections_configuration", "item": "11", "parent_collection": null, "parent_item": null, "parent_changed": false }, { "id": 227, "activity": 239, "collection": "app_collections_configuration", "item": "12", "parent_collection": null, "parent_item": null, "parent_changed": false } ] }
The permissions of Directus are very granular and will only improve in the next version(s).
@philleepflorence - this works for REST API, but then, when you try to sign in to GUI as an user with limited permissions, the app throws errors and eventually prevents you from signing in.
its been 2 years. Does anyone have solved this?