首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >保护存储过程

保护存储过程
EN

Stack Overflow用户
提问于 2010-11-12 16:57:58
回答 2查看 5.8K关注 0票数 2

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

我正在使用MySQL 5.1.48和.NET连接器6.2.3和Visual 2008 SP1。

在MySQL中有两个用户,一个是根用户(具有管理程序的所有权限),另一个是管理用户(具有特定模式中的select、update、insert、delete、create_temp_table、lock_table和execute权限)。

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

在我们开始创建DataSets并使用WebService之前,一切都很顺利,为此,管理用户需要表mysql中的列proc中的select权限。问题是,使用此权限,管理员可以查看所有存储过程,包括它们的内容。

请让我知道是否有办法保护SP的,我不知道这是修复的最新版本的MySQL和它是.Net连接器。

EN

回答 2

Stack Overflow用户

发布于 2010-11-12 18:42:52

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

因此,通常您有以下两个赠款给您的应用程序用户:

代码语言:javascript
复制
grant execute on foo_db.* to foo_dbo@localhost identified by 'pass';
grant select on mysql.proc to foo_dbo@localhost;

正如您正确地指出的,这是一个有点安全的问题,但我知道有一种方法可能会吓到您,但是,它工作得很好,实际上与标准方法(不考虑开销)相比,它具有更好的性能。

因此,在撤销mysql.proc上的授权选择和刷新特权之后.

代码语言:javascript
复制
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是我们的应用程序用户--他们只被授予执行permimissions,所以他们所能做的就是调用存储的procs;

代码语言:javascript
复制
call list_users();

所以我以root的身份登录并运行这个脚本demo_db.sql

代码语言:javascript
复制
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的身份登录,并开始创建我的模式对象:表、触发器、链表、视图等等.(别忘了demo_dbo是所有者,在demo_db内部可以随心所欲地做。)

所以我以demo_dbo的身份登录并运行这个脚本demo_dbo.sql

代码语言:javascript
复制
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身份登录时进行一些测试。

从表传递中选择

代码语言:javascript
复制
select * from users;
user_id
=======
1
2
3
4
5
6

调用存储过程-传递

代码语言:javascript
复制
call list_users();
user_id
=======
1
2
3
4
5
6

显示创建过程传递

代码语言:javascript
复制
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脚本:

显示表-失败

代码语言:javascript
复制
show tables;

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

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

从用户表中选择失败的

代码语言:javascript
复制
select * from users;
SELECT command denied to user 'demo_usr'@'localhost' for table 'users'

好的,正如预期的那样--他们不能直接访问表,所以我想他们获得数据的唯一方法就是通过我存储的procdure。

调用存储过程-传递

代码语言:javascript
复制
call list_users();
user_id
=======
1
2
3
4
5
6

最后是一个结果,但我们最好看看demo_usr能看到的关于这个sproc的什么信息。

显示创建过程失败的

代码语言:javascript
复制
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可以看到存储过程的存在(毕竟他们可以调用它),但是看不到身体。

演示应用

因此,我编写了这个快速而肮脏的C#应用程序,它使用MySQL .NET连接器(这是很棒的BTW),并尝试调用list_users()存储过程,并将datatable填充为应用程序用户demo_usr。

代码语言:javascript
复制
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();
        }
    }
}

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

代码语言:javascript
复制
oops - SELECT command denied to user 'demo_usr'@'localhost' for table 'proc'

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

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

那我们怎么才能避开这一切呢?那么,我们可以以demo_usr身份登录到mysql控制台,并从命令行调用存储过程,所以在应用程序代码中也可以这样做吗?

代码语言:javascript
复制
mysql> use demo_db;
Database changed
mysql> call list_users();
+---------+
| user_id |
+---------+
|       1 |
|       2 |
|       3 |
|       4 |
|       5 |
|       6 |
+---------+

因此,改变这条线:

代码语言:javascript
复制
 adr.SelectCommand.CommandType = CommandType.StoredProcedure;

代码语言:javascript
复制
adr.SelectCommand.CommandType = CommandType.Text;

我们现在..。

代码语言:javascript
复制
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

票数 3
EN

Stack Overflow用户

发布于 2010-11-12 17:06:32

可以使用GRANT将预分发限制为存储过程。

也许你可以用一些东西-

代码语言:javascript
复制
GRANT EXECUTE ON PROCEDURE db.storedproc TO 'username'@'somehost';

您可以找到GRANT 这里的完整语法。

编辑-

GRANT提供权限,而REVOKE则相反。您可以找到有关撤消这里的更多信息。

你可以试试-

代码语言:javascript
复制
FLUSH PRIVILEGES; 

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

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

代码语言:javascript
复制
REVOKE ALL PRIVILEGES ON db.* FROM username@somehost

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

代码语言:javascript
复制
REVOKE EXECUTE ON PROCEDURE db.storedproc FROM username;  

始终确保您没有不必要地授予全局特权。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4167110

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档