Prevent users from removing MySQL triggers set by different user - mysql

Im currently setting up a database system with a lot of different users, having access to only limited views, and tables of the database system.
Now I need to create several triggers as the root user, to prevent some actions. But all the users should be able to create a trigger for a database created for them and the tables within. This is working fine since every user has database-specific privileges. Sadly this does allow for some reason the user to delete triggers set by the root user on their database.
If I have database 'A' with table 'test'. I create a trigger as root user for database 'A' table 'test'. Now user 'someone' has privileges to create triggers for database 'A', but he should NOT be able to remove any trigger set by the root account on database 'A'. Sadly he can remove triggers created by root... anyone know how to fix this for MySQL?
Here is the privileges for the user for the specific database:
Now the query executed by the root user:
Result in with SHOW TRIGGERS executed by user 'someone' on database 'A':
Execution of DROP TRIGGER by user 'someone' on database 'A':
Why can the user remove this trigger? It's not created by him but root... Also for anyone asking, the query 'SELECT CURRENT_USER();' returns 'someone#localhost' and NOT 'root#localhost', i have activly switched accounts.

If you grant a user the TRIGGER privilege to create triggers on a given table, you grant them all the operations that privilege covers, which includes both create and drop
https://dev.mysql.com/doc/refman/8.0/en/drop-trigger.html says:
DROP TRIGGER requires the TRIGGER privilege for the table associated with the trigger.
It doesn't matter who defined the trigger. MySQL generally has no concept of ownership for database objects like tables or triggers.
You are going to have to think of a different design that does not require users to be disallowed this access.

Related

MySQL - 'Drop User' vs 'delete from user'

I need to delete database access from some hosts. There are two options:
This option appears to be the best as I don't need to delete individual users
use mysql;
delete from user where host='myhost';
In second option below, I need to delete individual users.
drop user 'user1'#'myhost';
drop user 'user2'#'myhost';
drop user 'user3'#'myhost';
Any idea what is the difference between these options? Any pro and cons?
Thanks
When you use DROP USER Statement it removed one/more accounts + their accounts privileges.
When you use DELETE User it's just an SQL command which effects for table(s).
DROP is always more powerful than delete
Or You can use REVOKE to remove all permeation granted
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'user'#'myhost';
Privileges are
ALL PRIVILEGES – grants all privileges to the MySQL user
CREATE – allows the user to create databases and tables
DROP - allows the user to drop databases and tables
DELETE - allows the user to delete rows from specific MySQL table
INSERT - allows the user to insert rows into specific MySQL table
SELECT – allows the user to read the database
UPDATE - allows the user to update table rows
Read More about DROP USER Statement
Modifying the database tables requires a flush privileges call to refresh the cached data. Also, you have to make sure that you manually delete all user AND privileges (e.g., for tables, columns) manually.
Grant/drop user work immediately.
Cf. https://dev.mysql.com/doc/refman/8.0/en/privilege-changes.html

Grant INSERT without having it

Grant INSERT without having it.
Suppose the following code snippet is executed every time a new manager is created (with different names for the database and user account each time, of course):
#Executed as root
CREATE DATABASE `Manager1Section`;
CREATE TABLE Manager1Data(`SomeData` INT);
CREATE USER 'Manager1'#'localhost' IDENTIFIED BY 'Something';
GRANT SELECT, INSERT, UPDATE, DELETE ON `Manager1Section`.`Manager1Data` TO 'Manager1'#'localhost';
GRANT CREATE, DROP ON `Manager1Section`.* TO 'Manager1'#'localhost';
GRANT CREATE USER ON *.* TO 'Manager1Section'#'localhost' WITH GRANT OPTION;
And the following code is executed every time a new intern is created (again, names substituted):
#Executed as manager
CREATE TABLE `Manager1Section`.`Intern1Data`(`Value` INT NOT NULL);
CREATE USER 'Intern1'#'localhost' IDENTIFIED BY 'Something';
GRANT SELECT, INSERT, UPDATE, DELETE ON `Manager1Section`.`Intern1Data` TO 'Intern1'#'localhost';
(Mind that this is just an example to show the hierarchical structure. I am not actually modeling a company's personnel structure.)
The manager manages a single database (Manager1Section in this example) and has a table to work with. The manager can only read and write to that table but not e.g. drop it. (Actually nevermind, I just realized that the manager can, in fact, drop the table. Not a big deal though.).
Each intern in this database also has a table to work with, and again, can only read and write to it but not drop it. Additionally, interns can only access their own tables, but not the manager's table and not other interns' tables.
And very importantly: The manager cannot read and write to interns' tables.
The above code would achieve this, but it is not valid. The last line in the second snippet fails. The manager does not have the SELECT, INSERT, UPDATE and DELETE privileges to interns' tables and therefore cannot grant those privileges to the interns. Changing the second-to-last line in the first snippet (GRANT CREATE, DROP ON `Manager1Section`.* TO 'Manager1'#'localhost';) to GRANT CREATE, DROP, SELECT, INSERT, UPDATE, DELETE ON `Manager1Section`.* TO 'Manager1'#'localhost'; makes that work but it also allows the manager to read and write to interns' tables, which I want to avoid.
How can I make the manager not able to read and write to interns' tables but still grant read and write privileges to interns?
Or alternatively: How can I avoid that problem altogether?
Only allowing users to grant privileges they already have is generally a good idea and my gut feeling tells me that my intended solution is not possible because the manager could circumvent the situation by creating a spoof intern account, executing GRANT SELECT, INSERT, UPDATE, DELETE ON `Manager1Section`.`Intern1Data` TO 'SpoofIntern'#'localhost'; (mind the mismatched user names) and then access the data through that account. But I could be missing something, so I am asking for ideas.

MySql: Restrict update permission on one column in one table

I have a table, lets call it student, in a schema called enrollment. Table student has a column called address that I don't want a certain user to update (other permissions are fine such as select, insert). All other columns in that table AND in that schema should have the update privilege.
Is this doable?
You can set privileges on database / table / column. But I really would not try to use MySQL's privilege mechanism at that level. I would instead write application code to decide who can see/change what. This is more flexible in the long run. And more graceful to the user -- instead of getting a cryptic MySQL error message about permissions, the UI would simply not show what should not be shown. For updating, the UI would not even give the user the option.
In my case, I wanted a specific application to be able to update only 1 field (my_field) in only 1 table (table_name) while being able to read the entire database.
I created a special user for that purpose:
CREATE USER 'restrictedUser'#'%' IDENTIFIED BY 'PASSWORD_HERE';
SET PASSWORD FOR 'restrictedUser'#'%' = PASSWORD('PASSWORD_HERE');
GRANT USAGE ON *.* TO 'restrictedUser'#'%';
GRANT SELECT ON DATABASE_NAME.* TO 'restrictedUser'#'%';
GRANT UPDATE (my_field) ON DATABASE_NAME.table_name TO 'restrictedUser'#'%';
Documentation for Column privilege can be found here for mariaDb and here for mysql

Is there a way to effectively GRANT on either TRUNCATE or DROP TABLE in MySQL?

I recently tried this in MySQL 5.5.x:
GRANT
SELECT, INSERT, UPDATE, DELETE, TRUNCATE ON crawler.*
TO 'my_user'#'localhost' WITH GRANT OPTION;
This results in an error:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TRUNCATE ON crawler.*
TO 'my_user'#'localhost' WITH GRANT OPTION' at line 2
This used to work before I added TRUNCATE, so after a bit of research I find that this is not supported in MySQL.
The reason for this is that TRUNCATE is classified as a DDL operation, and so it doesn't use DELETE internally, it uses DROP. Alright, so I'd like to restrict this user to dropping tables (in the event of a security breach, at least a malicious user would have to determine the names of tables and drop them individually).
However, it turns out I would need to grant this user the DROP privilege, which allows the user to drop whole databases too. Given that there is not a grant for individual tables, is there another way to do this? I suppose I could hand this off to another process with a different user, but it feels a bit cumbersome for such a small issue.
For the time being, I'll stick with DELETE, even though it is rather slow! (On my laptop it takes ~55 sec to delete 1.6M small rows, and a fraction of a second to truncate the same). However, I am all ears if there is a faster and secure alternative.
To grant DROP privilege on a specific table in a specific database to a specific user in MySQL, you can use a GRANT statement like this. (This assumes that table fi exists in database fee, and this is the table you want to allow the user 'fo'#'%' to be able to TRUNCATE):
GRANT DROP ON TABLE fee.fi TO 'fo'#'%'
To see that the user has privilege to truncate that specific table:
SHOW GRANTS FOR 'fo'#'%' ;
And connect as user 'fo'#'%' to test:
TRUNCATE TABLE fee.fi ;
(Obviously, the user also has the privilege to DROP that same table. But that's just the way it is in MySQL.)
As an alternative, to allow the user to perform only the TRUNCATE operation on that specific table, without granting the user DROP privilege on the table...
create a stored procedure that performs a TRUNCATE fee.fi; (That will probably need to be executed dynamically since it's DDL.) The procedure will need to be created with DEFINER privileges, and created by a user that has the required privileges.
Then you can grant execute on the procedure to the user:
GRANT EXECUTE ON fee.truncate_table_fee_fi TO 'fo'#'%';
Then user 'fo'#'%' can
CALL fee.truncate_table_fee_fi

Grant users to create database with username

In phpmyadmin I want to grant users to create and delete databases but this access should be limited to a specific prefix.
My users have 3 different accounts on PhpMyAdmin: username_ro (for only reading), username_rw (for reading and writing) and username_admin (for creating other databases and tables into their account)
I want them to be able to create a database username_website but I don't want them to be able to create database theother_website. They should also be able to drop username_website but unable to drop theother_website
How can I do this with sql or PhpMyAdmin.
Thanks in advance.
With some trial and error I have found a solution. By doing this query I was able to create and drop database username_website but I wasn't able to create or drop database theother_clients
GRANT ALL PRIVILIGES
ON `username\_%`.*
TO 'username_admin'#'localhost';
PS. the query is a little edited. I changed the rights I actually gave with ALL PRIVILIGESand I changed the actual username with username.