mysql> create database remove_test; Query OK, 1 row affected (0,05 sec)Create a user with privileges on the database created in previous step:
mysql> grant all privileges on remove_test.* to test_user@'%' identified by 'test'; Query OK, 0 rows affected, 1 warning (0,20 sec)Connect to the database using the user created:
$ mysql -u test_user -ptest remove_testCreate a view, check the attributes and execute it. We are going to use a couple of functions that I will explain a bit later.
mysql> create view test_view as select current_user(),user(); Query OK, 0 rows affected (0,05 sec) mysql> show create view test_view\G *************************** 1. row *************************** View: test_view Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`test_user`@`%` SQL SECURITY DEFINER VIEW `test_view` AS select current_user() AS `current_user()`,user() AS `user()` character_set_client: utf8 collation_connection: utf8_general_ci 1 row in set (0,00 sec) mysql> select * from test_view; +----------------+---------------------+ | current_user() | user() | +----------------+---------------------+ | test_user@% | test_user@localhost | +----------------+---------------------+ 1 row in set (0,00 sec)As we can see, the view has been created with SQL SECURITY DEFINER and DEFINER=`test_user`@`%`. The view returns the value from two functions: current_user() returns the value that matches against the mysql.user table and that defines the privileges the current session or current execution context has. The function user() returns the host you are connected from and the username specified as connection identifier. Now we reconnect to the database using the privileged account from the first step, and requery the view:
$ mysql -u root -p remove_test mysql> select * from test_view; +----------------+----------------+ | current_user() | user() | +----------------+----------------+ | test_user@% | root@localhost | +----------------+----------------+ 1 row in set (0,00 sec)The view is executed by root@localhost but with the privileges of test_user@%. It is important to note that if you monitor the execution of a routine or view, using SHOW PROCESSLIST or query against information_schema.processlist, the contents of user and host are the same that current_user() return, not the ones returned by user(). Now we will drop the user and query once again the view.
mysql> drop user test_user@'%';
Query OK, 0 rows affected (0,07 sec)
mysql> select * from test_view;
ERROR 1449 (HY000): The user specified as a definer ('test_user'@'%') does not exist In case you don’t see the error and still get the correct results, this is because the contents of the view are stored in the query cache. Clear their contents and repeat the query.
mysql> reset query cache; Query OK, 0 rows affected (0,00 sec)How to validate if it is safe to remove a user? You must query the information_schema tables to find objects than can bring problems and recreate them.
mysql> select routine_schema as db, -> routine_type as object_type, -> routine_name as object_name -> from routines -> where security_type='DEFINER' -> and definer='test_user@%' -> union all -> select trigger_schema as db, -> 'TRIGGER' as object_type, -> trigger_name as object_name -> from triggers -> where definer='test_user@%' -> union all -> select table_schema as db, -> 'VIEW' as object_type, -> table_name as object_name -> from views -> where security_type='DEFINER' -> and definer='test_user@%'; +-------------+-------------+-------------+ | db | object_type | object_name | +-------------+-------------+-------------+ | remove_test | VIEW | test_view | +-------------+-------------+-------------+ 1 row in set (0,02 sec)Replace test_user@% with the value of the user you want to remove. This way you get a list of the objects you must change to avoid problems. As I said before the best thing you can do to change the definer is recreating the objects. To obtain the creation script you should use SHOW CREATE VIEW, SHOW CREATE TRIGGER, SHOW CREATE PROCEDURE or SHOW CREATE FUNCTION. If you want to avoid problems in the future, my recommendation is that for every application, create an account for that application, lock it with an unknown password or using account locking feature. Grant that account all the privileges needed to run the application and make sure all the views, procedures, functions and triggers have that account in the definer field.
On this page
Share this
Share this
More resources
Learn more about Pythian by reading the following blogs and articles.
How to use procedures to increase security in MySQL
How to use procedures to increase security in MySQL
Sep 20, 2018 12:00:00 AM
4
min read
When the ALTER TABLE privilege is not enough to run ALTER TABLE
When the ALTER TABLE privilege is not enough to run ALTER TABLE
Mar 1, 2010 12:00:00 AM
2
min read
Working with resource groups in MySQL 8
Working with resource groups in MySQL 8
Sep 5, 2018 12:00:00 AM
4
min read
Ready to unlock value from your data?
With Pythian, you can accomplish your data transformation goals and more.