保护存储过程

时间:2010-11-12 16:57:58

标签: mysql stored-procedures privileges

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

我正在使用MySQL 5.1.48和Net Connector 6.2.3与Visual Studio 2008 SP1。

我在MySQL中有两个用户,一个是root(具有管理porpuses的所有权限),另一个是admin(在特定模式中具有select,update,insert,delete,create_temp_table,lock_table和execute特权)。 / p>

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

在我们开始创建DataSet并使用WebService之前,一切正常,因此管理员用户需要 proc 列中的选择权限来自表 mysql 即可。问题是,使用此权限,管理员可以查看所有存储过程,包括其内容。

请告诉我是否有保护SP的方法,我不知道这是否已在最新版本的MySQL及其.Net连接器中修复。

2 个答案:

答案 0 :(得分:3)

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

通常,您的应用用户可以获得以下两笔拨款:

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_db ),有两个用户demo_dbo和demo_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_db架构

好了,现在我有一个数据库可以播放,接下来我以demo_dbo身份登录并开始创建我的模式对象:表,触发器,sprocs,视图等...(不要忘记demo_dbo是所有者,可以这样做他们喜欢里面的demo_db)

所以我以 demo_dbo 的身份登录并运行此脚本demo_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个sproc)所以我最好在我还是以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

好的,看起来很棒 demo_dbo (所有者)可以在demo_db中完成他们应该做的所有事情,所以现在我们最好测试一下我们的demo_usr可以达到的目的。

我以 demo_usr 登录并运行demo_usr.sql脚本:

显示表格 - 失败

show tables;

Tables_in_demo_db
=================
NULL

没什么可看的 - 对于demo_usr来说,他们甚至看不到数据库中的表格是多么令人失望。

从用户表中选择 - 失败

select * from users;
SELECT command denied to user 'demo_usr'@'localhost' for table 'users'

按预期正常 - 他们无法直接访问表格,所以我猜他们获取数据的唯一方法是通过我的存储过程API。

调用存储过程 - 通过

call list_users();
user_id
=======
1
2
3
4
5
6

最后一个结果,但我们最好看看demo_usr可以看到的关于这个sproc的信息......

显示创建程序 - 失败

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可以看到存储的procdure存在(毕竟它们可以调用它)但是看不到正文。

演示应用程序

所以我敲了一下使用MySQL .NET连接器(这是很棒的BTW)的快速和脏 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();
        }
    }
}

好的,这失败了 - 为什么?这是异常消息:

oops - SELECT command denied to user 'demo_usr'@'localhost' for table 'proc'

请记住,我们只为demo_usr授予了demo_usr的执行权限 - 没有别的!!

现在我们可以通过在mysql.proc上给它们选择perms来解决这个问题,但是如果我们这样做,它们将能够看到存储过程体 - 我们想要避免它。

那么我们如何解决这个问题呢?那么我们可以作为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;

adr.SelectCommand.CommandType = CommandType.Text;

我们现在得到......

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

答案 1 :(得分:0)

您可以使用GRANT限制对存储过程的预留。

也许你可以使用像 -

这样的东西
GRANT EXECUTE ON PROCEDURE db.storedproc TO 'username'@'somehost';

您可以找到GRANT here

的完整语法

编辑 -

GRANT是提供权限而REVOKE是与它相反的。您可以找到有关REVOKE here的更多信息。

您可以尝试使用 -

FLUSH PRIVILEGES; 

这将重新加载mysql数据库中的授权表的权限。

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

REVOKE ALL PRIVILEGES ON db.* FROM username@somehost

要撤消特定存储过程的用户执行授权,您可以使用

REVOKE EXECUTE ON PROCEDURE db.storedproc FROM username;  

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

相关问题