MYSQL 决定性、权限问题

BEGIN 
    UPDATE mysql.proc
    SET is_deterministic = 'YES',
            security_type = 'INVOKER';
            
-- PM_Add_OperateRecord
-- PM_Del_ReportRate
-- PR_Del_RiskStrategeUser
-- PR_Mod_RiskForcePrice
END 

  最近在做项目升级,之前所有项目链接数据库都是使用的root账户,为了安全考虑给项目单独开了个用户,添加了增删改查  以及execute权限,但是项目在调用存储过程是仍然报错,说没有权限,查询之后发现除了execute外,还需要得有mysql库上user表的权限

另外  备注:

【definer和invoker的解释】

    创建存储过程的时候可以指定 SQL SECURITY属性,设置为 DEFINER 或者INVOKER,用来奉告mysql在执行存储过程的时候,,是以DEFINER用户的权限来执行,还是以调用者的权限来执行。

   默认情况下,使用DEFINER方式,此时调用存储过程的用户必须有存储过程的EXECUTE权限,并且DEFINER指定的用户必须是在mysql.user表中存在的用户。

   DEFINER模式下,默认DEFINER=CURRENT_USER,在存储过程执行时  mysql 会检查DEFINER定义的用户'user_name'@'host_name'的权限;

   INVOKER模式下,在存储过程执行时,会检查存储过程调用者的权限。

因为CREATE PROCEDURE, CREATE FUNCTION, ALTER PROCEDURE,ALTER FUNCTION,CALL, DROP PROCEDURE, DROP FUNCTION等语句都会被写进二进制日志,然后在从服务器上执行。但是,一个执行更新的不确定子程序(存储过程、函数、触发器)是不可重复的,在从服务器上执行(相对与主服务器是重复执行)可能会造成恢复的数据与原始数据不同,从服务器不同于主服务器的情况。

为了解决这个问题,MySQL强制要求:
在主服务器上,除非子程序被声明为确定性的或者不更改数据,否则创建或者替换子程序将被拒绝。
这意味着当创建一个子程序的时候,必须要么声明它是确定性的,要么它不改变数据。

声明方式有两种,
第一种:声明是否是确定性的
DETERMINISTIC和NOT DETERMINISTIC指出一个子程序是否对给定的输入总是产生同样的结果。
如果没有给定任一特征,默认是NOT DETERMINISTIC,所以必须明确指定DETERMINISTIC来声明一个子程序是确定性的。 
这里要说明的是:使用NOW() 函数(或它的同义)或者RAND() 函数不会使一个子程序变成非确定性的。对NOW()而言,二进制日志包括时间戳并会被正确的执行。RAND()只要在一个子程序内被调用一次也可以被正确的复制。所以,www.linuxidc.com可以认为时间戳和随机数种子是子程序的确定性输入,它们在主服务器和从服务器上是一样的。

第二种:声明是否会改变数据  
CONTAINS SQL, NO SQL, READS SQL DATA, MODIFIES SQL用来指出子程序是读还是写数据的。
无论NO SQL还是READS SQL DATA都指出,子程序没有改变数据,但是必须明确地指定其中一个,因为如果任何指定,默认的指定是CONTAINS SQL。

默认情况下,如果允许CREATE PROCEDURE 或CREATE FUNCTION 语句被接受,就必须明确地指定DETERMINISTIC 或 NO SQL与READS SQL DATA 中的一个,否则就会产生1418错误。

解决方法:

解决办法也有两种,
第一种是在创建子程序(存储过程、函数、触发器)时,声明为DETERMINISTIC或NO SQL与READS SQL DATA中的一个,
例如:
CREATE DEFINER = CURRENT_USER PROCEDURE `NewProc`()
    DETERMINISTIC
BEGIN
 #Routine body goes here...
END;;

第二种是信任子程序的创建者,禁止创建、修改子程序时对SUPER权限的要求,设置log_bin_trust_routine_creators全局系统变量为1。设置方法有三种:
1.在客户端上执行SET GLOBAL log_bin_trust_function_creators = 1;
2.MySQL启动时,加上--log-bin-trust-function-creators选贤,参数设置为1
3.在MySQL配置文件my.ini或my.cnf中的[mysqld]段上加log-bin-trust-function-creators=1

网络上的其他方案.也是一样的

创建function时

出错信息:

ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

 

原因:

这是我们开启了bin-log, 我们就必须指定我们的函数是否是
1 DETERMINISTIC 不确定的
2 NO SQL 没有SQl语句,当然也不会修改数据
3 READS SQL DATA 只是读取数据,当然也不会修改数据
4 MODIFIES SQL DATA 要修改数据
5 CONTAINS SQL 包含了SQL语句

其中在function里面,只有 DETERMINISTIC, NO SQL 和 READS SQL DATA 被支持。如果我们开启了 bin-log, 我们就必须为我们的function指定一个参数。


在MySQL中创建函数时出现这种错误的解决方法:
set global log_bin_trust_function_creators=TRUE;

问题:

随着项目开发的推进,数据库用到的表越来越多,数据之间的整合性要求越来越高,针对较为复杂的跨多表的数据业务级别的约束,我们通过触发器以及存储过程来替代大量的后台判断代码,效率较高且便捷。在使用过程中,遇到一些问题,其中最突出的是在数据库迁移过程中,经常会有存储过程,因为权限问题,无法被执行。调查发现,创建过程中的会默认指定definer或者invoker,具体参见mysql.proc的security_type,由sql_security指定。下面主要讨论definer的使用问题。

实验:

1.执行如下的sql语句,创建一个存储过程

DROP PROCEDURE IF EXISTS `clearMission`;
DELIMITER ;;
CREATE DEFINER=`li`@`192.168.200.1` PROCEDURE `clearMission`()
BEGIN

 XXXXXXXX


END
;;
DELIMITER ;

执行后,我们创建了一个存储过程

,注意,此处的definer字段如果不指定值得话,默认是当前登陆者本人,所以,我们也可以创建definer是root@localhost的存储过程,前提是这个用户存在(用户具体存在与否以及他的权限,可以参照mysql.user),

2.执行我们刚刚创建的存储过程

执行存储过程时,mysql会检查执行权限,顺序如下

当前执行者是否有权限执行存储过程,具体参见mysql.user的execute字段

如果当前执行者可以执行该存储过程,继续检查该存储体的definer字段或者invoker字段定义的用户是否有权限,如果有,则执行成功,如果无,则报错

综上,当我们在定义存储过程时,definer或者invoker指定的用户必须要有执行存储过程的权限。

3.修改存储过程

能否修改既存的存储过程,要看该用户的权限 mysql.user的Alter_routine_priv字段。这个比较简单,只要有权限,就可以更改。

但是开发过程中,我们使用navicat的时候,遇到一个实际问题,描述如下:

在ip为192.168.52.1的机器上,A用户定义了一个存储过程A,definer为xx@192.168.52.1

在ip为192.168.52.2的机器上,B用户要查看该存储过程(B用户有查看的权限),使用nvicat,发现存储体的begin和end之间的内容无法查看,但B可以执行。并且用命令行可以显示。

另外,如果A在定义的时候,指定definer为root@localhost,则B就可以通过nvicat查看修改执行该存储体。或许这个问题是nvicat本身的使用问题,而不是mysql的机制。目前,通过定义成root解决存储体的共享问题。

附上mysql.user表字段详解,注意,每次修改完权限之后 要执行flush privileges命令或者重启服务器,否则修改的权限不起作用。

Select_priv。确定用户是否可以通过SELECT命令选择数据。
Insert_priv。确定用户是否可以通过INSERT命令插入数据。
Update_priv。确定用户是否可以通过UPDATE命令修改现有数据。
Delete_priv。确定用户是否可以通过DELETE命令删除现有数据。
Create_priv。确定用户是否可以创建新的数据库和表。
Drop_priv。确定用户是否可以删除现有数据库和表。
Reload_priv。确定用户是否可以执行刷新和重新加载MySQL所用各种内部缓存的特定命令,包括日志、权限、主机、查询和表。
Shutdown_priv。确定用户是否可以关闭MySQL服务器。在将此权限提供给root账户之外的任何用户时,都应当非常谨慎。
Process_priv。确定用户是否可以通过SHOW PROCESSLIST命令查看其他用户的进程。
File_priv。确定用户是否可以执行SELECT INTO OUTFILE和LOAD DATA INFILE命令。
Grant_priv。确定用户是否可以将已经授予给该用户自己的权限再授予其他用户。例如,如果用户可以插入、选择和删除foo数据库中的信息,并且授予了GRANT权限,则该用户就可以将其任何或全部权限授予系统中的任何其他用户。
References_priv。目前只是某些未来功能的占位符;现在没有作用。
Index_priv。确定用户是否可以创建和删除表索引。
Alter_priv。确定用户是否可以重命名和修改表结构。
Show_db_priv。确定用户是否可以查看服务器上所有数据库的名字,包括用户拥有足够访问权限的数据库。可以考虑对所有用户禁用这个权限,除非有特别不可抗拒的原因。
Super_priv。确定用户是否可以执行某些强大的管理功能,例如通过KILL命令删除用户进程,使用SET GLOBAL修改全局MySQL变量,执行关于复制和日志的各种命令。
Create_tmp_table_priv。确定用户是否可以创建临时表。
Lock_tables_priv。确定用户是否可以使用LOCK TABLES命令阻止对表的访问/修改。
Execute_priv。确定用户是否可以执行存储过程。此权限只在MySQL 5.0及更高版本中有意义。
Repl_slave_priv。确定用户是否可以读取用于维护复制数据库环境的二进制日志文件。此用户位于主系统中,有利于主机和客户机之间的通信。
Repl_client_priv。确定用户是否可以确定复制从服务器和主服务器的位置。
Create_view_priv。确定用户是否可以创建视图。此权限只在MySQL 5.0及更高版本中有意义。关于视图的更多信息,参见第34章。
Show_view_priv。确定用户是否可以查看视图或了解视图如何执行。此权限只在MySQL 5.0及更高版本中有意义。关于视图的更多信息,参见第34章。
Create_routine_priv。确定用户是否可以更改或放弃存储过程和函数。此权限是在MySQL 5.0中引入的。
Alter_routine_priv。确定用户是否可以修改或删除存储函数及函数。此权限是在MySQL 5.0中引入的。
Create_user_priv。确定用户是否可以执行CREATE USER命令,这个命令用于创建新的MySQL账户。
Event_priv。确定用户能否创建、修改和删除事件。这个权限是MySQL 5.1.6新增的。
Trigger_priv。确定用户能否创建和删除触发器,这个权限是MySQL 5.1.6新增的。

 

 

 

 

 

 

 

 

 

 

 

procedure与function、trigger等创建时紧接着CREATE都有个definer可选项,该definer规定了访问该procedure等的安全控制。

CREATE DEFINER = `bigdata1`@`192.168.%` PROCEDURE `Test`()
BEGIN
   ......
END;
1
2
3
4
上面示例指定definer为用户bigdata1@192.168.%,所以任意用户A访问该PROCEDURE 时,能否成功取决于A是否有调用该PROCEDURE的权限,以及definer是否有procedure中的SELECT的权限。

DEFINER默认为当前用户,也可指定其他用户。如果想通过访问者来判断是否具有访问该PROCEDURE 的权限,则可用SQL SECURITY指定。

CREATE DEFINER = `bigdata1`@`192.168.%` PROCEDURE `Test`()
    SQL SECURITY INVOKER
BEGIN
   ......
END;
1
2
3
4
5
该示例虽然指定了DEFINER ,但同时也指定了SQL SECURITY 类型为INVOKER ,SQL SECURITY 优先级高,所以安全类型为INVOKER,用户能否访问取决于用户是否有执行该PROCEDURE 的权限及该PROCEDURE 中的SELECT 权限(与select操作的表有关)。 
当然,也可用SQL SECURITY 指定DEFINER:SQL SECURITY DEFINER

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值