Selecionar permissão dentro do procedimento armazenado?

8

Eu concedi a um usuário permissão de execução para um procedimento armazenado que usa SQL dinâmico. Mas quando ele tenta executá-lo, ele recebe o erro:

A permissão SELECT foi negada no objeto '[nome da tabela]', banco de dados '[nome do banco de dados]', esquema 'dbo'.

O usuário precisa de permissão para alguma tabela que o procedimento armazenado use? Isso realmente não faria sentido para mim.

xdumaina
fonte

Respostas:

5

Ok, com base no comentário acima e conforme minha suspeita - parece que você está tentando executar SQL dinâmico dentro do seu procedimento armazenado.

O que você precisa lembrar é que, quando você faz isso, ele não é executado no contexto do procedimento armazenado - ele é executado em uma nova sessão. Por esse motivo, o fato de a instrução estar sendo chamada em um procedimento armazenado é um ponto discutível e você precisará conceder permissão explícita nos objetos que seu SQL dinâmico está usando.

Se você não quiser fazer isso, refatoraria seu procedimento armazenado para não usar SQL dinâmico.

O link abaixo da Microsoft deve ajudá-lo com o seu problema:

PRB: Contexto de segurança de instruções SQL dinâmicas dentro de um procedimento armazenado (arquivo Wayback Machine)

Esse comportamento ocorre porque uma consulta de execução dinâmica (sp_executesql ou EXECUTE) é executada em um contexto separado do procedimento armazenado principal; ele é executado no contexto de segurança do usuário que executa o procedimento armazenado e não no contexto de segurança do proprietário do procedimento armazenado.

Isso também é discutido no artigo (mais atual) do Microsoft Docs:

Gravando SQL dinâmico seguro no SQL Server

A execução de instruções SQL criadas dinamicamente em seu código processual interrompe a cadeia de propriedade, fazendo com que o SQL Server verifique as permissões do chamador com relação aos objetos acessados ​​pelo SQL dinâmico.

DBA Mundial
fonte
2

Parece que existem diferentes proprietários do procedimento, bem como o objeto subjacente que o SELECT está consultando. Tudo isso tem a ver com cadeias de propriedade . Veja o exemplo abaixo para uma breve explicação e demonstração do que estou falando:

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

Se você deseja descobrir a propriedade de seus objetos, pode executar a consulta abaixo (obviamente alterando a cláusula WHERE para incluir seus nomes de objetos específicos):

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'
);
Thomas Stringer
fonte