授予具有有限访问权限的数据库用户执行权限会产生什么后果?

3
如果我有一个只拥有有限权限的用户 - 只有db_datareader和db_datawriter,这应该只允许用户查询数据并插入/编辑/删除数据,而不允许用户添加/修改/删除数据库中的表。
可能需要让用户能够执行存储过程。如果用户被授予执行权限(通过以下sql语句:“GRANT EXECUTE TO UserName”),那么之前的限制(datareader和datawriter)是否仍然会强制执行用户尝试通过存储过程执行的操作?或者执行权限是否真的会打开其他安全漏洞的“潘多拉魔盒”(如果是这样,是哪些漏洞)?
4个回答

5
如果存储过程的所有者有权针对表执行选择、插入、更新或删除操作,那么只要调用方对存储过程具有执行权限,存储过程中的选择、插入、更新和删除语句就会执行,即使调用方没有直接对表执行选择、插入、更新或删除的权限。
但是,除非调用方有DDL权限,否则存储过程不能执行DDL,即使存储过程的所有者具有DDL权限。请注意,这也适用于截断表操作。
答案:在您的情况下,授予用户db_datareaderdb_datawriter已经赋予了用户对所有表的完全DML权限。对任何存储过程授予执行权限将不会增加任何其他权限。
存储过程可用于通过提供所有外部程序必须经过的门来增加数据完整性。不要授予插入、删除或更新权限,而是创建执行工作并强制执行有关数据的适当规则的存储过程(超出约束所能做到的)。正如Joe Kuemerle指出的那样,存储过程可以用于增加安全性。
我在SQL Server 2000上开发应用程序时观察到了这种行为,并在SQL Server 2008上重新测试后发现了相同的行为。我无法找到有关此行为的文档。
以DBO和SA登录并创建表:
create table dbo.SO (PK int identity constraint SO_PK primary key
    , SomeData varchar(1000)
)

接下来创建一些基本的DML存储过程:

create procedure dbo.InsertSO (@SomeData varchar(1000)) as
    begin
    insert into dbo.SO (SomeData) values (@SomeData)
    return SCOPE_IDENTITY()
    end
go

create procedure dbo.SelectSO (@PK int=null) as
    begin
    if @PK is not null
        select PK, SomeData from dbo.SO where PK = @PK
    else
        select PK, SomeData from dbo.SO
    end
go

create procedure dbo.CountSO as
    begin
    select COUNT(*) as CountSO from SO
    end
go

create procedure dbo.DeleteSO (@PK int=null ) as
    begin
    if @PK is not null
        delete dbo.SO where PK = @PK
    else
        delete dbo.SO
    end
go

create procedure dbo.UpdateSO (@PK int, @NewSomeData varchar(1000)) as
    begin`
    update dbo.SO
    set SomeData =  @NewSomeData
    where PK = @PK
    end
go

create procedure dbo.TruncateSO as
    begin
    truncate table dbo.SO
    end
go

作为dbo,我们可以运行以下SQL语句:
declare @PK_to_update int
insert into dbo.SO (SomeData) values ('Hello world!')
set @PK_to_update = SCOPE_IDENTITY()

declare @PK_to_delete int
insert into dbo.SO (SomeData) values ('Goodbye cruel world!')
set @PK_to_delete = SCOPE_IDENTITY()

insert into dbo.SO (SomeData) values ('Four score and seven years ago...')

select PK, SomeData
from dbo.SO

delete dbo.so
where PK = @PK_to_delete

update dbo.SO
set SomeData = 'Hello Milky Way!'
where PK = @PK_to_update

select PK, SomeData
from dbo.SO

truncate table dbo.SO

select COUNT(*) as CountSO from dbo.SO

或者通过存储过程来完成相应的操作

go
declare @PK_to_update int
exec @PK_to_update = dbo.InsertSO 'Hello world!'

declare @PK_to_delete int
exec @PK_to_delete = dbo.InsertSO 'Goodbye cruel world!'

exec dbo.InsertSO 'Four score and seven years ago...'

exec dbo.SelectSO 

exec dbo.DeleteSO @PK_to_delete

exec dbo.UpdateSO @PK_to_update, 'Hello Milky Way!'

exec dbo.SelectSO

exec dbo.TruncateSO

exec dbo.CountSO

现在,创建一个 DDL 存储过程并进行测试:
create procedure dbo.DropSO as
    begin 
    drop table dbo.SO
    end
go
begin transaction
select TABLE_NAME from INFORMATION_SCHEMA.TABLES
where TABLE_NAME = 'SO'
exec dbo.DropSO
select TABLE_NAME from INFORMATION_SCHEMA.TABLES
where TABLE_NAME = 'SO'
rollback transaction

现在创建另一个用户,并授予所有存储过程的执行权限。不要授予任何其他权限。(假设公共用户没有额外的权限和混合模式身份验证。不建议使用混合模式身份验证,但可以使测试权限处理更容易。)

exec sp_addlogin @loginame =  'SoLogin' , @passwd = 'notsecure', @defdb = 'Scratch'

exec sp_adduser @loginame = 'SoLogin', @name_in_db = 'SoUser'
go
grant execute on dbo.InsertSo to SoUser 
grant execute on dbo.InsertSO to SoUser
grant execute on dbo.SelectSO to SoUser
grant execute on dbo.CountSO to SoUser
grant execute on dbo.DeleteSO to SoUser
grant execute on dbo.UpdateSO to SoUser
grant execute on dbo.TruncateSO to SoUser
grant execute on dbo.DropSO to SoUser

以SoLogin身份登录。尝试使用DML:

declare @PK_to_update int
insert into dbo.SO (SomeData) values ('Hello world!')
set @PK_to_update = SCOPE_IDENTITY()

declare @PK_to_delete int
insert into dbo.SO (SomeData) values ('Goodbye cruel world!')
set @PK_to_delete = SCOPE_IDENTITY()

insert into dbo.SO (SomeData) values ('Four score and seven years ago...')

select PK, SomeData
from dbo.SO

delete dbo.so
where PK = @PK_to_delete

update dbo.SO
set SomeData = 'Hello Milky Way!'
where PK = @PK_to_update

select PK, SomeData
from dbo.SO

truncate table dbo.SO
go
select COUNT(*) as CountSO from dbo.SO
go

drop table dbo.so

只有错误:

Msg 229, Level 14, State 5, Line 2
The INSERT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 6
The INSERT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 9
The INSERT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 11
The SELECT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 14
The SELECT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 14
The DELETE permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 17
The SELECT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 17
The UPDATE permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 229, Level 14, State 5, Line 21
The SELECT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 1088, Level 16, State 7, Line 24
Cannot find the object "SO" because it does not exist or you do not have permissions.
Msg 229, Level 14, State 5, Line 1
The SELECT permission was denied on the object 'SO', database 'Scratch', schema 'dbo'.
Msg 3701, Level 14, State 20, Line 2
Cannot drop the table 'SO', because it does not exist or you do not have permission.

尝试基本的DML存储过程:

declare @PK_to_update int
exec @PK_to_update = dbo.InsertSO 'Hello world!'

declare @PK_to_delete int
exec @PK_to_delete = dbo.InsertSO 'Goodbye cruel world!'

exec dbo.InsertSO 'Four score and seven years ago...'

exec dbo.SelectSO 

exec dbo.DeleteSO @PK_to_delete

exec dbo.UpdateSO @PK_to_update, 'Hello Milky Way!'

exec dbo.SelectSO

他们起作用是因为SP的所有者拥有正确的权限,即使SoUser没有。

尝试使用截断或删除存储过程:

exec dbo.TruncateSO
go
exec dbo.DropSO

再次出现错误:

Msg 1088, Level 16, State 7, Procedure TruncateSO, Line 4
Cannot find the object "SO" because it does not exist or you do not have permissions.
Msg 3701, Level 14, State 20, Procedure DropSO, Line 4
Cannot drop the table 'SO', because it does not exist or you do not have permission.

1
这个方法之所以可行(并且将继续可行)是因为 SQL Server 有一个叫做所有权链的特性。由于表和存储过程都有相同的所有者(dbo),SQL 允许对象的共同所有者修改这些对象。因此,一个由 dbo 拥有的存储过程可以操作表(也由 dbo 拥有)而无需进行额外的安全检查。这在这里有所讨论:http://blogs.msdn.com/lcris/archive/2007/09/13/basic-sql-server-security-concepts-ownership-chaining-good-and-evil-schemas.aspx。 - Joe Kuemerle
@Joe:感谢提供链接,很有启发性。当你说“...共同拥有对象以修改这些对象...”时,我发现这些修改仅限于通过选择、插入、删除和更新语句修改对象中的数据。你不能修改对象本身。即使是 truncate 也不能在默认情况下使用所有权链。我发现文档对这些问题不够清晰,并通过上面提供的示例尝试说明即使调用者没有权限,也可以在存储过程内完成哪些操作和不能完成哪些操作。 - Shannon Severance
授予执行所有存储过程的权限是否允许接收者运行位于数据库中的系统存储过程(sys.*)?这难道不是一个安全风险吗? - undefined

2
执行权限不会增加任何额外的安全漏洞。在我看来,更大的漏洞是用户直接具有对表的读写访问权限。
由于SQL Server实现了所有权链,您可以通过撤销数据读取器/数据编写器权限并通过存储过程提供所有数据访问来提供可控、可审计的数据访问。这将确保某人无法随意地向表中插入/更新/删除数据。它还将在深度防御策略中提供另一层保护,因为如果使用数据库的应用程序容易受到SQL注入攻击,攻击者不能读取/写入他们想要的任何表。
唯一需要注意的是,如果您正在使用ORM,则可能需要一些额外的开发工作来使用存储过程而不是让ORM动态生成SQL。

1

你需要的概念是 "所有权链"

基本上,存储过程使用的同一架构(例如dbo)中的对象不会进行权限检查。除了:拒绝权限始终被检查。

因此,如果存储过程dbo.uspDoStuff使用表dbo.Parent和dbo.Child,则不需要对表进行权限控制,它就可以正常工作。除非你运行了"DENY SELECT ON dbo.Parent to MyUser"。

注意:通常你会执行"CREATE ROLE MyRole",将用户添加到角色中,并授予角色权限。db_datareader只是一个特殊的保留角色。


0

授予执行权限将允许该人在存储过程的上下文中执行存储过程所执行的任何操作(因此,如果存储过程删除表,则用户将能够执行存储过程以删除该表)。

编辑,我刚刚检查发现我错了。拒绝访问不会撤销对存储过程中执行操作的能力。

以下是 MSDN 上的文章,指定拒绝访问对存储过程不会产生影响。

http://msdn.microsoft.com/en-us/library/bb669058.aspx

更新: 您可能能够通过在存储过程中使用sp_executeSQL执行一个drop table命令,并拒绝用户删除表的权限。这应该可以防止存储过程成功执行该命令(除非用户有权限这样做),因为要使用sp_executesql,用户需要具有执行sql操作而不仅仅是访问存储过程的权限。


所以在问题中概述的情况下,如果我明确拒绝用户的Drop Table权限,那么即使存储过程有SQL语句来删除表,当用户尝试执行它时,他们也将被拒绝? - Yaakov Ellis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接