背景
用户反馈实例视图无法访问,与用户沟通后,了解到近期安全变更将部分用户绑定的ip从%变为客户端ip地址,发生故障后,用户紧急进行了回滚,视图访问恢复正常,业务恢复。
分析
首先mysql族的关系数据库,账户组成由user@ip共同决定,对其中任意结构的变更都将破坏原来账户的定义。 针对于用户的描述,包括关键行为:1、删除账户(变更相当于删除之前的账户);2、视图无法使用;3、修复账户后又恢复。我们估计是视图的definer被删除导致,查看用户故障视图,果然发现其定义者就是被删除的用户。换一种说话,由于视图definer(由user@ip组成)在mysql.user表中被移除,导致该视图无法正常提供访问。
代码语言:javascript复制### https://mariadb.com/kb/en/create-view/
If you specify the DEFINER clause, these rules determine the legal DEFINER user values:
If you do not have the SUPER privilege, the only legal user value is your own account, either specified literally or by using CURRENT_USER. You cannot set the definer to some other account.
If you have the SUPER privilege, you can specify any syntactically legal account name. If the account does not actually exist, a warning is generated.
If the SQL SECURITY value is DEFINER but the definer account does not exist when the view is referenced, an error occurs.
其流程图可以展示为:
扩展
我们以一个测试的mariadb视图创建语句来做分析
代码语言:javascript复制MariaDB [alan]> show create view aaaG
*************************** 1. row ***************************
View: aaa
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`vky`@`%` SQL SECURITY DEFINER VIEW `aaa` AS select `alan`.`ha`.`id` AS `id`,`alan`.`ha`.`name` AS `name` from `ha`
character_set_client: utf8
collation_connection: utf8_general_ci
1 row in set, 1 warning (0.00 sec)
其中view列的意义是视图的名称,character_set_client列和collation_connection列为视图使用到的字符集和排序规则; create view当中包含了视图的主体结构,分类列举: 1、ALGORITHM=UNDEFINED ALGORITHM表示实例对视图的处理算法,这个参数有三个值,包括MERGE、TEMPTABLE以及缺省值UNDEFINED,其中merge可以简单的理解为将外部的sql语句和视图定义的语句合并起来,到原表进行查询;TEMPTABLE与merge相对应,他将视图中的结果先储存到临时表,外部sql直接调用临时表中的结果;至于UNDEFINED,可以理解为实例按照场景自己决定使用哪一个处理算法。 2、DEFINER=`vky`@`%` DEFINER表示视图的定义者(包括用户名以及绑定的ip),通常可以显式的指定,缺省值为当前用户,也就是select current_user();返回的用户。 3、SQL SECURITY DEFINER SQL SECURITY约束视图的安全性策略,他的值有DEFINER和INVOKER。其中DEFINER的策略为如果引用者存有引用该视图的权限(该视图的select权限),通常可以成功返回结果;如果为INVOKER,他需要引用视图的账户也需要同时对视图中的原表具有select的权限,否则也会返回报错。
回到我们故障场景,用户修改了视图定义者的host之后,导致视图无法访问,这里我们前面也进行了充分的解释,更进一步,既然不能破坏user@host这个结构,那我们破坏掉这个用户的权限从而来实现软删除的目的可以不呢?我们对SQL SECURITY 解释中,默认definer策略下,当前账户只需要有试图的select权限即可以正常的引用,其中对原表数据访问实际上使用到了定义者的权限,如果我们对定义者的权限进行完全破坏,实际上也是会失去对视图的使用。以下截屏是我们测试的结果:
代码语言:javascript复制MariaDB [alan]> show grants for vky@'%';
--------------------------------------------------------------------------------------------------------
| Grants for vky@% |
--------------------------------------------------------------------------------------------------------
| GRANT USAGE ON *.* TO 'vky'@'%' IDENTIFIED BY PASSWORD '*96A12F0614169E80CC46E92BDE3DBF0FD4751D7C' |
--------------------------------------------------------------------------------------------------------
1 row in set (0.00 sec)
MariaDB [alan]> select * from aaa;
ERROR 1356 (HY000): View 'alan.aaa' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
MariaDB [alan]> show grants for vky@'%'G
*************************** 1. row ***************************
Grants for vky@%: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER ON *.* TO 'vky'@'%' IDENTIFIED BY PASSWORD '*96A12F0614169E80CC46E92BDE3DBF0FD4751D7C'
1 row in set (0.00 sec)
MariaDB [alan]> select * from aaa;
---- ------
| id | name |
---- ------
| 1 | alan |
| 2 | joke |
| 3 | tom |
---- ------
3 rows in set (0.00 sec)
同样的逻辑,在invoker策略下,虽然删除定义者不会影响其它拥有权限的用户引用视图,但是这里也跑偏了创建视图的初衷。
那要如何完成变更definer操作呢?
由于云上实例通常不存在super权限,所以无法直接使用super账户直接将视图从a归属到b名下,但是却可以使用b账户登录实例,对视图进行definer的变更操作。如截屏:
代码语言:javascript复制MariaDB [alan]> show create table aaaG
*************************** 1. row ***************************
View: aaa
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`vky`@`%` SQL SECURITY DEFINER VIEW `aaa` AS select `ha`.`id` AS `id`,`ha`.`name` AS `name` from `ha`
character_set_client: utf8
collation_connection: utf8_general_ci
1 row in set (0.00 sec)
MariaDB [alan]> alter ALGORITHM=UNDEFINED DEFINER=`vky`@`10.%` SQL SECURITY DEFINER VIEW `aaa` AS select `ha`.`id` AS `id`,`ha`.`name` AS `name` from `ha`;
Query OK, 0 rows affected (0.00 sec)
MariaDB [alan]> show create table aaaG
*************************** 1. row ***************************
View: aaa
Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`vky`@`10.%` SQL SECURITY DEFINER VIEW `aaa` AS select `ha`.`id` AS `id`,`ha`.`name` AS `name` from `ha`
character_set_client: utf8
collation_connection: utf8_general_ci
1 row in set (0.00 sec)
MariaDB [alan]> select current_user();
----------------
| current_user() |
----------------
| vky@10.% |
----------------
1 row in set (0.00 sec)
MariaDB [alan]>
该操作完成之后,,用户方可进行对高风险用户(绑定%的用户)进行回收操作。