在存储过程中选择权限?


8

我已授予用户使用动态SQL的存储过程的执行权限。但是当他尝试执行它时,他得到了错误:

对对象“ [表名]”,数据库“ [数据库名]”,模式“ dbo”的SELECT权限被拒绝。

是否需要向用户授予存储过程使用的任何表的权限?这对我来说真的没有任何意义。

Answers:


5

好的,根据以上评论,并且根据我的怀疑,似乎您正在尝试在存储过程中执行动态SQL。

您需要记住的是,执行此操作时,它不会在存储过程的上下文中执行-而是在新会话中执行。因此,在存储过程中调用该语句这一事实是有争议的,您将需要为动态SQL使用的对象授予显式权限。

如果您不想这样做,我会将您的存储过程重构为不使用动态SQL。

Microsoft的以下链接应帮助您解决问题:

PRB:存储过程中的动态SQL语句的安全上下文(Wayback Machine存档)

因为动态执行查询(sp_executesql或EXECUTE)在与主存储过程不同的上下文中执行,所以会发生此现象。它在执行存储过程的用户的安全上下文中执行,而不是在存储过程的所有者的安全上下文中执行。

(最新的)Microsoft Docs文章也对此进行了讨论:

在SQL Server中编写安全的动态SQL

在过程代码中执行动态创建的SQL语句会中断所有权链,导致SQL Server根据动态SQL访问的对象检查调用方的权限。


2

听起来好像有不同的过程所有者以及SELECT查询的基础对象。这一切与所有权链有关。请参阅以下示例,以简要说明和演示我正在谈论的内容:

use YourTestDatabase;
go

create login TestLogin1
with 
    password = 'password',
    check_policy = off;
go

create user TestUser1
for login TestLogin1;
go

create table Table1
(
    id int identity(1, 1) not null,
    SomeString varchar(30) not null
        default replicate('a', 30)
);
go

insert into Table1
values(default);
go 10

create proc Proc1
as
    select *
    from Table1;
go


grant execute
on Proc1
to TestUser1;
go

-- this works because permissions aren't checked
--  on Table1.  That is why TestUser1 can get the
--  result set without SELECT permissions on Table1
execute as user = 'TestUser1';
go

exec Proc1;
go

revert;
go

-- let's change the owner of Proc1 so that the 
--  ownership chain is broken and permissions are
--  checked on Table1
alter authorization
on Proc1
to TestUser1;
go

-- this no longer works because permissions are now
--  checked on Table1, which TestUser1 does not have
--  SELECT permissions on
execute as user = 'TestUser1';
go

exec Proc1;
go

revert;
go

如果要查找对象的所有权,则可以运行以下查询(显然是通过更改WHERE子句以包括您的特定对象名称):

select
    o.name,
    o.type_desc,
    case
        when o.principal_id is null
            then sp.name
        else dp.name
    end as principal_name
from sys.objects o
inner join sys.schemas s
on o.schema_id = s.schema_id
left join sys.database_principals dp
on o.principal_id = dp.principal_id
left join sys.database_principals sp
on s.principal_id = sp.principal_id
where o.name in
(
    'Table1',
    'Proc1'
);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.