Pilih izin di dalam prosedur tersimpan?

8

Saya telah memberikan izin kepada pengguna untuk prosedur tersimpan yang menggunakan SQL dinamis. Tetapi ketika dia mencoba untuk mengeksekusinya, dia mendapatkan kesalahan:

Izin SELECT ditolak pada objek '[nama tabel]', database '[nama database]', skema 'dbo'.

Apakah pengguna perlu diberikan izin untuk setiap tabel yang menggunakan prosedur tersimpan? Itu tidak masuk akal bagi saya.

xdumaine
sumber

Jawaban:

5

Ok, berdasarkan komentar di atas dan sesuai kecurigaan saya - sepertinya Anda mencoba untuk mengeksekusi SQL dinamis dalam prosedur tersimpan Anda.

Yang perlu Anda ingat adalah bahwa ketika Anda melakukan ini tidak dieksekusi dalam konteks prosedur tersimpan - itu dieksekusi dalam sesi baru. Karena itu, fakta bahwa pernyataan itu dipanggil dalam prosedur tersimpan adalah titik diperdebatkan, dan Anda perlu memberikan izin eksplisit pada objek yang menggunakan SQL dinamis Anda.

Jika Anda tidak ingin melakukan ini, saya akan memperbaiki prosedur tersimpan Anda untuk tidak menggunakan SQL dinamis.

Tautan di bawah ini dari Microsoft akan membantu Anda dengan masalah Anda:

PRB: Konteks Keamanan Pernyataan SQL Dinamis di dalam Prosedur yang Disimpan (arsip Wayback Machine)

Perilaku ini terjadi karena permintaan eksekusi dinamis (sp_executesql atau EXECUTE) dieksekusi dalam konteks terpisah dari prosedur tersimpan utama; ini dijalankan dalam konteks keamanan pengguna yang mengeksekusi prosedur tersimpan dan tidak dalam konteks keamanan pemilik prosedur tersimpan.

Ini juga dibahas dalam artikel Microsoft Documents (lebih terkini):

Menulis Secure Dynamic SQL dalam SQL Server

Menjalankan pernyataan SQL yang dibuat secara dinamis dalam kode prosedural Anda memutus rantai kepemilikan, menyebabkan SQL Server untuk memeriksa izin pemanggil terhadap objek yang diakses oleh SQL dinamis.

World Wide DBA
sumber
2

Kedengarannya seperti ada pemilik prosedur yang berbeda serta objek yang mendasari bahwa SELECT meminta. Ini semua ada hubungannya dengan Rantai Kepemilikan . Lihat contoh di bawah ini untuk penjelasan dan demonstrasi singkat tentang apa yang saya bicarakan:

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

Jika Anda ingin mengetahui kepemilikan objek Anda, Anda dapat menjalankan kueri di bawah ini (jelas dengan mengubah klausa WHERE untuk memasukkan nama objek spesifik Anda):

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
sumber