Mysql 保护存储过程

Mysql 保护存储过程,mysql,stored-procedures,privileges,Mysql,Stored Procedures,Privileges,我想知道是否有办法对某些用户隐藏存储过程的文本 我正在使用MySQL 5.1.48和NetConnector 6.2.3以及VisualStudio2008SP1 我在MySQL中有两个用户,一个是root用户(具有管理权限),另一个是admin用户(具有特定模式中的选择、更新、插入、删除、创建临时表、锁定表和执行权限) 所有存储过程都是由root用户创建的,因此管理员用户只能在不知道它们如何工作或读取其内容的情况下执行它们 在我们开始创建数据集和使用WebService之前,一切都很正常,为此

我想知道是否有办法对某些用户隐藏存储过程的文本

我正在使用MySQL 5.1.48和NetConnector 6.2.3以及VisualStudio2008SP1

我在MySQL中有两个用户,一个是root用户(具有管理权限),另一个是admin用户(具有特定模式中的选择、更新、插入、删除、创建临时表、锁定表和执行权限)

所有存储过程都是由root用户创建的,因此管理员用户只能在不知道它们如何工作或读取其内容的情况下执行它们

在我们开始创建数据集和使用WebService之前,一切都很正常,为此,管理员用户需要表mysqlproc列中的select权限。问题是,使用此权限,管理员可以查看所有存储过程,包括其内容


请告诉我是否有保护SP的方法,我不知道最新版本的MySQL及其.Net connector是否修复了此问题。

您可以使用
GRANT
将预授权限制在存储过程中

也许你可以用一些东西,比如-

GRANT EXECUTE ON PROCEDURE db.storedproc TO 'username'@'somehost';
您可以找到GRANT的完整语法

编辑-

GRANT是提供权限,REVOKE是做相反的事情。您可以找到有关吊销的更多信息

你可以尝试使用-

FLUSH PRIVILEGES; 
这将从mysql数据库中的grant表重新加载权限

如果用户已具有执行权限,并且您希望撤销该用户的所有权限,则可以使用-

REVOKE ALL PRIVILEGES ON db.* FROM username@somehost
要撤消用户对特定存储过程的执行授权,可以使用

REVOKE EXECUTE ON PROCEDURE db.storedproc FROM username;  

始终确保您不会不必要地授予全局权限。

通常,在将MySQL.NET连接器与存储过程结合使用时,您必须授予“应用程序用户”对MySQL.proc的select权限,否则连接器无法看到您试图通过它调用的存储过程

因此,通常你会为你的应用程序用户获得以下两项授权:

grant execute on foo_db.* to foo_dbo@localhost identified by 'pass';
grant select on mysql.proc to foo_dbo@localhost;
正如您正确指出的,这是一个安全问题,但我知道有一种方法可以解决它,这可能会让您感到害怕,但是,它的工作非常好,并且实际上与标准方法(思考较少的开销)的性能相同,甚至更高

所以在撤销mysql.proc上的授予选择和刷新权限后

string sqlCmd = string.Format("call list_users({0})", userType);

MySqlConnection cn = new MySqlConnection();
cn.ConnectionString = "Server=....";

adr = new MySqlDataAdapter(sqlCmd, cn);
adr.SelectCommand.CommandType = CommandType.Text; // change from sproc to CommandType.Text
dt = new DataTable();
adr.Fill(dt); //opens and closes the DB connection automatically !!
希望这有帮助:)

编辑:由于我的答案引起了一些混乱,我想我应该添加一个完整的问题解决方案,正如我所看到的那样

创建演示数据库 只有一个快速演示数据库(demo\u db),有两个用户demo\u dbo和demo\u usr

demo_dbo被授予对demo_db的完全权限-他们是数据库所有者(dbo),可以在该数据库中随心所欲,例如创建、删除、创建过程、截断等

demo_usr是我们的应用程序用户-他们只被授予执行权限,所以他们所能做的就是调用存储的进程

call list_users();
因此,我以root登录并运行这个脚本demo_db.sql

drop database if exists demo_db;

create database demo_db
character set latin1
default character set latin1
collate latin1_swedish_ci
default collate latin1_swedish_ci;

revoke select on mysql.* from demo_dbo@localhost;
revoke all privileges on demo_db.* from demo_dbo@localhost;
revoke grant option on *.* from demo_dbo@localhost;
drop user demo_dbo@localhost;

revoke select on mysql.* from demo_usr@localhost;
revoke all privileges on demo_db.* from demo_usr@localhost;
revoke grant option on *.* from demo_usr@localhost;
drop user demo_usr@localhost;

grant all on demo_db.* to demo_dbo@localhost identified by 'pass';
grant select on mysql.* to demo_dbo@localhost;

grant execute on demo_db.* to demo_usr@localhost identified by 'pass';

flush privileges;

select host, user from mysql.user;
创建演示数据库模式 好了,现在我有一个数据库要玩,所以下一步我以demo_dbo的身份登录并开始创建我的模式对象:表、触发器、存储过程、视图等等。。。(别忘了demo_dbo是所有者,可以在demo_db中随心所欲)

因此,我以demo\u dbo的身份登录并运行这个脚本demo\u dbo.sql

use demo_db;

drop table if exists users;
create table users(
 user_id int unsigned not null auto_increment primary key
)
engine=innodb;

insert into users values (null),(null),(null),(null),(null),(null);

drop procedure if exists list_users;

delimiter #

create procedure list_users()
begin
    select * from users order by user_id;
end #

delimiter ; 
好的,这是创建的demo_db模式(1个表和1个存储过程),所以我最好在仍然以demo_dbo身份登录时进行一些测试

从表格中选择-通过

select * from users;
user_id
=======
1
2
3
4
5
6
call list_users();
user_id
=======
1
2
3
4
5
6
show create procedure list_users;

Procedure   sql_mode    Create Procedure    character_set_client    collation_connection    Database Collation
=========   ========    ================    ====================    ====================    ==================
list_users      CREATE DEFINER=`demo_dbo`@`localhost` PROCEDURE `list_users`()
begin
    select * from users order by user_id;
end utf8    utf8_general_ci latin1_swedish_ci
call list_users();
user_id
=======
1
2
3
4
5
6
调用存储过程-通过

select * from users;
user_id
=======
1
2
3
4
5
6
call list_users();
user_id
=======
1
2
3
4
5
6
show create procedure list_users;

Procedure   sql_mode    Create Procedure    character_set_client    collation_connection    Database Collation
=========   ========    ================    ====================    ====================    ==================
list_users      CREATE DEFINER=`demo_dbo`@`localhost` PROCEDURE `list_users`()
begin
    select * from users order by user_id;
end utf8    utf8_general_ci latin1_swedish_ci
call list_users();
user_id
=======
1
2
3
4
5
6
显示创建过程-通过

select * from users;
user_id
=======
1
2
3
4
5
6
call list_users();
user_id
=======
1
2
3
4
5
6
show create procedure list_users;

Procedure   sql_mode    Create Procedure    character_set_client    collation_connection    Database Collation
=========   ========    ================    ====================    ====================    ==================
list_users      CREATE DEFINER=`demo_dbo`@`localhost` PROCEDURE `list_users`()
begin
    select * from users order by user_id;
end utf8    utf8_general_ci latin1_swedish_ci
call list_users();
user_id
=======
1
2
3
4
5
6
好的,一切看起来都很好,demo_dbo(所有者)可以在demo_db内部完成所有他们应该能够完成的事情,所以现在我们最好测试我们的demo_usr可以达到什么

我以demo\u usr身份登录并运行demo\u usr.sql脚本:

显示表格-失败

show tables;

Tables_in_demo_db
=================
NULL
select * from users;
SELECT command denied to user 'demo_usr'@'localhost' for table 'users'
show create procedure list_users;
Procedure   sql_mode    Create Procedure    character_set_client    collation_connection    Database Collation
=========   ========    ================    ====================    ====================    ==================
list_users          utf8    utf8_general_ci latin1_swedish_ci
没什么可看的-对于demo_usr来说,他们甚至看不到数据库中的表是多么令人失望

从用户表中选择-失败

show tables;

Tables_in_demo_db
=================
NULL
select * from users;
SELECT command denied to user 'demo_usr'@'localhost' for table 'users'
show create procedure list_users;
Procedure   sql_mode    Create Procedure    character_set_client    collation_connection    Database Collation
=========   ========    ================    ====================    ====================    ==================
list_users          utf8    utf8_general_ci latin1_swedish_ci
正如预期的那样-他们不能直接访问表,所以我想他们获取数据的唯一方法是通过我的存储过程API

调用存储过程-通过

select * from users;
user_id
=======
1
2
3
4
5
6
call list_users();
user_id
=======
1
2
3
4
5
6
show create procedure list_users;

Procedure   sql_mode    Create Procedure    character_set_client    collation_connection    Database Collation
=========   ========    ================    ====================    ====================    ==================
list_users      CREATE DEFINER=`demo_dbo`@`localhost` PROCEDURE `list_users`()
begin
    select * from users order by user_id;
end utf8    utf8_general_ci latin1_swedish_ci
call list_users();
user_id
=======
1
2
3
4
5
6
最后是一个结果,但我们最好看看演示可以看到关于这个存储过程的哪些信息

显示创建过程-失败

show tables;

Tables_in_demo_db
=================
NULL
select * from users;
SELECT command denied to user 'demo_usr'@'localhost' for table 'users'
show create procedure list_users;
Procedure   sql_mode    Create Procedure    character_set_client    collation_connection    Database Collation
=========   ========    ================    ====================    ====================    ==================
list_users          utf8    utf8_general_ci latin1_swedish_ci
demo_usr可以看到存储过程的存在(毕竟他们可以调用它),但看不到主体

演示应用程序 因此,我开发了这个使用MySQL.NET连接器的快速脏C#应用程序(顺便说一句,它很棒),并尝试调用list_users()存储过程,并填充一个数据表作为应用程序用户demo_usr

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using MySql.Data;
using MySql.Data.MySqlClient;
using System.Data;

namespace demo_db
{
    class Program
    {
        static void Main(string[] args)
        {
            MySqlConnection cn = new MySqlConnection("Server=127.0.0.1;Uid=demo_usr;Pwd=pass;Database=demo_db;");
            MySqlDataAdapter adr = null;
            try
            {
                DataTable dt = new DataTable();
                adr = new MySqlDataAdapter("call list_users", cn);
                adr.SelectCommand.CommandType = CommandType.StoredProcedure;
                adr.Fill(dt); //opens and closes the DB connection automatically !!
                foreach (DataRow dr in dt.Rows)
                    Console.WriteLine(string.Format("user_id = {0}", dr.Field<uint>("user_id").ToString()));
            }
            catch(Exception ex)
            {
                Console.WriteLine(string.Format("oops - {0}", ex.Message));            
            }
            finally
            {
                adr.Dispose();
                cn.Dispose();
            }
            Console.WriteLine("\nPress any key to quit.");
            Console.ReadKey();
        }
    }
}
请记住,我们只为demo_db授予demo_usr的执行权限-没有其他

现在我们可以通过在mysql.proc上授予他们select perm来解决这个问题,但是如果我们这样做,他们将能够看到存储过程体——这是我们想要避免的

那么我们该如何应对呢?我们可以作为demo_usr登录mysql控制台,从命令行调用一个存储过程,这样在应用程序代码中也可以这样做

mysql> use demo_db;
Database changed
mysql> call list_users();
+---------+
| user_id |
+---------+
|       1 |
|       2 |
|       3 |
|       4 |
|       5 |
|       6 |
+---------+
因此,改变路线:

 adr.SelectCommand.CommandType = CommandType.StoredProcedure;

我们现在得到

user_id = 1
user_id = 2
user_id = 3
user_id = 4
user_id = 5
user_id = 6

Press any key to quit.
太好了,它很管用

希望这有帮助


Rgds f00

什么是“数据集”和“Web服务”,为什么它需要访问“mysql”数据库?读起来有点像“我把我家钥匙给了我的朋友,我怎样才能阻止他进入我家?”读起来很好-你只需要知道他在说什么。@f00-问题,如果用户管理员可以从proc中选择,这是否意味着他可以做
show create produre xxx
?show create过程需要在mysql.proc上进行授权选择,那么如果管理员