我想知道是否有办法对某些用户隐藏存储过程的文本。
我正在使用带有 Visual Studio 2008 SP1 的 MySQL 5.1.48 和 Net Connector 6.2.3。
我在 MySQL 中有两个用户,一个是 root(具有管理 porpuses 的所有权限),另一个是 admin(在特定模式中具有选择、更新、插入、删除、create_temp_table、lock_table 和执行权限)。
所有存储过程都由 root 用户创建,因此 admin 用户只能在不知道它们如何工作或阅读其内容的情况下执行它们。
一切正常,直到我们开始创建数据集并使用 WebService,为此管理员用户需要 选择 列中的特权过程 从表 mysql .问题是,有了这个权限,管理员可以看到所有的存储过程,包括它们的内容。
请让我知道是否有办法保护 SP,我不知道这是否在最新版本的 MySQL 中修复,它是 .Net 连接器。
最佳答案
通常,当将 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();
所以我登录为 根并运行此脚本 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、 View 等......(不要忘记 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 身份登录的情况下进行一些测试。
从表中选择 - PASS
select * from users;
user_id
=======
1
2
3
4
5
6
调用存储过程 - PASS
call list_users();
user_id
=======
1
2
3
4
5
6
显示创建过程 - PASS
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。
调用存储过程 - PASS
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 可以看到存储过程存在(他们毕竟可以调用它)但看不到正文。
演示应用程序
因此,我启动了这个使用 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();
}
}
}
好的,这失败了 - 为什么?这是异常消息:
oops - SELECT command denied to user 'demo_usr'@'localhost' for table 'proc'
请记住,我们只为 demo_db 授予了 demo_usr 的执行权限 - 没有别的!!
现在我们可以通过在 mysql.proc 上授予他们选择权限来解决这个问题,但如果我们这样做,他们将能够看到存储过程体——这是我们想要避免的。
那么我们如何解决这个问题呢?那么我们可以作为 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
关于mysql - 保护存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4167110/