Выбрать разрешение внутри хранимой процедуры?


8

Я предоставил пользователю разрешение на выполнение хранимой процедуры, которая использует динамический SQL. Но когда он пытается выполнить его, он получает ошибку:

В доступе SELECT было отказано для объекта «[имя таблицы]», базы данных «[имя базы данных]», схемы «dbo».

Нужно ли пользователю предоставлять разрешение для каких-либо таблиц, которые использует хранимая процедура? Это не имеет никакого смысла для меня.

Ответы:


5

Хорошо, на основании приведенного выше комментария и, по моему подозрению, кажется, что вы пытаетесь выполнить динамический SQL в рамках вашей хранимой процедуры.

Следует помнить, что когда вы делаете это, он не выполняется в контексте хранимой процедуры - он выполняется в новом сеансе. Из-за этого тот факт, что оператор вызывается внутри хранимой процедуры, является спорным вопросом, и вам необходимо предоставить явное разрешение на объекты, которые использует ваш динамический SQL.

Если вы не хотите этого делать, я бы реорганизовал вашу хранимую процедуру, чтобы не использовать динамический SQL.

Ниже ссылка от Microsoft должна помочь вам с вашей проблемой:

PRB: контекст безопасности динамических операторов SQL внутри хранимой процедуры (архив Wayback Machine)

Это происходит потому, что динамический запрос выполнения (sp_executesql или EXECUTE) выполняется в отдельном контексте от основной хранимой процедуры; он выполняется в контексте безопасности пользователя, который выполняет хранимую процедуру, а не в контексте безопасности владельца хранимой процедуры.

Это также обсуждается в (более актуальной) статье Microsoft Docs:

Написание безопасного динамического SQL в SQL Server

Выполнение динамически созданных операторов 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'
);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.