概述
分享一个比较神奇的现象,是我们的开发人员在开发环境因为不规范操作发现的,后来研究了一下是mysql权限控制方面的问题,下面分享一下这个问题的解决过程。
问题
问题:用root用户在数据库lcpdb创建函数getUnitChildList可以看到函数内容,但是普通用户账号只能看到函数存在,看不到函数内容,无法修改,且无法调用。而且,普通账号可以删除这些存储过程并重建。
下面介绍下排查时的思路:
1、查看权限
有大佬说这个问题是由于是赋权是采用 all privileges的方式进行赋权的,这种赋权方式,是没有函数等存储过程使用的权限。需要重新给普通用户赋权。因为我们授权刚好是使用这种方式,还是挺符合的。
定义该存储过程还需要有CREATE ROUTINE的权限、更改存储过程需要有ALTER ROUTINE的权限(这里是用超级用户在lcpdb创建的存储过程,上述权限都是具备的),调用存储过程的用户需要有EXECUTE权限,最终执行存储过程的用户也即存储过程定义者要具备存储过程定义语句中相关的各种权限。
2、重新授权
alter routine---修改与删除存储过程/函数
create routine--创建存储过程/函数
execute--调用存储过程/函数
grant execute on lcpdb.* to 'fsl'@'%' grant execute on lcpdb.* to 'fsl'@'localhost' grant create routine on lcpdb.* to 'fsl'@'%' grant create routine on lcpdb.* to 'fsl'@'localhost' grant alter routine on lcpdb.* to 'fsl'@'localhost' grant alter routine on lcpdb.* to 'fsl'@'%' flush privileges;
授权后查看函数还是不行,之所以在命令行操作是考虑有可能在navicat看不到,但是命令行可以看到的情况。
3、考虑definer
在mysql创建view、trigger、function、procedure、event时都会定义一个Definer=‘xxx’
SQL SECURITY { DEFINER | INVOKER } :指明谁有权限来执行。DEFINER 表示按定义者拥有的权限来执行
INVOKER 表示用调用者的权限来执行。默认情况下,系统指定为DEFINER
以存储过程为例:
(1)MySQL存储过程是通过指定SQL SECURITY子句指定执行存储过程的实际用户; (2)如果SQL SECURITY子句指定为DEFINER,存储过程将使用存储过程的DEFINER执行存储过程,验证调用存储过程的用户是否具有存储过程的execute权限和DEFINER用户是否具有存储过程引用的相关对象的权限; (3)如果SQL SECURITY子句指定为INVOKER,那么MySQL将使用当前调用存储过程的用户执行此过程,并验证用户是否具有存储过程的execute权限和存储过程引用的相关对象的权限; (4)如果不显示的指定SQL SECURITY子句,MySQL默认将以DEFINER执行存储过程。 因为fsl对函数getUnitChildList有执行的权限,但是它依旧没有权限直接操作mysql库,由于我们定义的SQL SECURITY为DEFINER,所以在执行时是以root的身份执行的,所以可以正常查询出来,普通用户没有mysql权限
这里执行命令:
grant all privileges on mysql.* to 'fsl'@'%'
可以查询select * from mysql.proc来查看权限。
到这里问题就解决了。
这里按数据库管理规范还是建议root只做权限方面的控制,不同数据库用不同用户来管理,不要用root来直接创建函数,这样也就不会有这种情况发生啦!