MySQL存储对象访问控制

时间:2019-11-20 08:52:32  来源:igfitidea点击:

简介:在本教程中,您将了解MySQL中的存储对象访问控制。

在MySQL中,存储例程(存储过程和函数),触发器,事件和视图在确定其特权的安全上下文中执行。

MySQL使用DEFINER和SQL SECURITY特性来控制这些特权。

DEFINER属性

定义存储例程(例如存储过程或函数)时,可以选择指定DEFINER属性,该属性是MySQL帐户的名称:

CREATE [DEFINER=user] PROCEDURE spName(parameter_list)
...

CREATE [DEFINER=user] FUNCTION sfName()
...

如果跳过DEFINER属性,则默认值为当前用户帐户。

如果您具有SUPER或SET_USER_ID特权,则可以在DEFINER属性中指定任何帐户。
如果指定的用户帐户不存在,MySQL将发出警告。

从MySQL 8.0.16开始,您必须具有SYSTEM_USER特权才能将存储对象的DEFINER属性设置为具有SYSTEM_USER特权的用户帐户。

SQL SECURITY特征

存储的例程(存储的过程和函数)和视图可以包含SQL SECURITY子句​​,其值为DEFINER或INVOKER:

CREATE [DEFINER=user] PROCEDURE spName(parameter_list)
SQL SECURITY [DEFINER | INVOKER]
...

CREATE [DEFINER=user] FUNCTION sfName(parameter_list)
SQL SECURITY [DEFINER | INVOKER]
...

SQL安全定义器

当您对存储的对象使用SQL SECURITY DEFINER时,它将以DEFINER属性指定的用户权限在定义者安全上下文中执行。

请注意,调用存储对象(或调用者)的用户可能没有与定义者相同的特权。

如果调用者具有最少的特权,而定义者具有最多的特权,则调用者可以在存储的对象中执行超出其特权的操作。

SQL安全调用程序

如果将SQL SECURITY INVOKER用于存储的例程或视图,则它将在调用者的特权内运行。

DEFINER属性在对象执行期间不起作用。

存储对象访问控制示例

首先,创建一个名为testdb的新数据库:

CREATE DATABASE testdb;

其次,选择要使用的数据库testdb:

USE testdb;

第三,创建一个名为message的新表:

CREATE TABLE messages (
    id INT AUTO_INCREMENT,
    message VARCHAR(100) NOT NULL,
    PRIMARY KEY (id)
);

第四,创建一个存储过程,将新行插入到messages表中:

DELIMITER $$

CREATE DEFINER = root@localhost PROCEDURE InsertMessage( 
    msg VARCHAR(100)
)
SQL SECURITY DEFINER
BEGIN
    INSERT INTO messages(message)
    VALUES(msg);
END$$

DELIMITER ;

在此存储过程中,定义者为root @ localhost,它是具有所有特权的超级用户。

SQL安全设置为定义器。
这意味着任何调用此存储过程的用户帐户都将以定义者的所有特权执行,即root @ localhost用户帐户。

第五,创建一个名为dev @ localhost的新用户:

CREATE USER dev@localhost 
IDENTIFIED BY 'Abcd1234';

第六,将EXECUTE特权授予dev @ localhost,以便它可以执行testdb数据库中的任何存储过程:

GRANT EXECUTE ON testdb.* 
TO dev@localhost;

第七,使用dev @ localhost登录到MySQL服务器:

mysql -u dev@localhost -p

八,使用SHOW DATABASES显示dev @ localhost可以访问的数据库:

mysql> show databases;

这是清单:

+--------------------+
| Database           |
+--------------------+
| information_schema |
| testdb             |
+--------------------+
2 rows in set (0.00 sec)

第九,选择testdb数据库:

mysql> use testdb;

第十,调用InsertMessage过程将一行插入到message表中:

mysql> call InsertMessage('Hello World');

这是输出:

Query OK, 1 row affected (0.01 sec)

即使dev @ localhost在messages表上没有任何特权,它也可以通过存储过程将新行成功插入到该表中,因为存储过程是在root @ localhost用户帐户的安全上下文中执行的。

第十一,转到root用户的会话并创建一个存储过程来更新messages表:

DELIMITER $$

CREATE DEFINER=root@localhost 
PROCEDURE UpdateMessage( 
    msgId INT,
    msg VARCHAR(100)
)
SQL SECURITY INVOKER
BEGIN
    UPDATE messages
    SET message = msg
    WHERE id = msgId;
END$$

DELIMITER ;

UpdateMessage具有INVOKER的安全上下文,INVOKER将调用此存储过程。

第十二,转到dev @ localhost的会话,并调用UpdateMessage()存储过程:

mysql> call UpdateMessage(1,'Good Bye');

这次,UpdateMessage()存储过程以调用者dev @ localhost的特权执行。

由于dev @ localhost在messages表上没有任何特权,因此MySQL会发出错误并拒绝更新:

ERROR 1142 (42000): UPDATE command denied to user 'dev'@'localhost' for table 'messages'

在本教程中,您了解了MySQL存储对象访问控制。