Obawiam się, że Twój opis lub koncepcja wiązania własności są niejasne, więc zacznę od tego:
„Łańcuch własności” odnosi się po prostu do faktu, że podczas wykonywania procedury przechowywanej (lub widoku) na serwerze SQL Server, aktualnie wykonywana partia tymczasowo nabywa prawa/uprawnienia właściciela sProc (lub właściciela schematu sProc) podczas wykonywania tego kodu SQL. Tak więc w przypadku sProc, Użytkownik nie może używać tych uprawnień do robienia czegokolwiek, czego kod sProc nie implementuje dla nich. Zwróć szczególną uwagę, że nigdy nie uzyskuje tożsamości Właściciela, tylko jego prawa, tymczasowo (jednak EXECUTE AS... robi to).
Dlatego typowym podejściem do wykorzystania tego dla bezpieczeństwa jest:
-
Umieść wszystkie tabele danych (i wszystkie widoki niezwiązane z zabezpieczeniami) w ich własnym schemacie, nazwijmy to [dane] (chociaż zwykle używa się [dbo], ponieważ już tam jest i jest zbyt uprzywilejowany dla schematu użytkownika). Upewnij się, że żaden istniejący użytkownicy, schematy ani właściciele nie mają dostępu do tego schematu [danych].
-
Utwórz schemat o nazwie [exec] dla wszystkich sProcs (i/lub ewentualnie widoków bezpieczeństwa). Upewnij się, że właściciel tego schematu ma dostęp do schematu [data] (jest to łatwe, jeśli ustawisz dbo jako właściciela tego schematu).
-
Utwórz nową rolę db-Role o nazwie „Użytkownicy” i nadaj jej dostęp EXECUTE do schematu [exec]. Teraz dodaj wszystkich użytkowników do tej roli. Upewnij się, że Twoi użytkownicy mają tylko uprawnienia Connect i nie mają dostępu do żadnego innego schematu, w tym [dbo].
Teraz Twoi użytkownicy mogą uzyskać dostęp do danych tylko poprzez wykonanie sProcs w [exec]. Nie mogą uzyskać dostępu do żadnych innych danych ani wykonywać żadnych innych obiektów.
Nie jestem pewien, czy to odpowiada na twoje pytanie (ponieważ nie byłem pewien, jakie dokładnie było pytanie), więc możesz mnie przekierować.
Jeśli chodzi o zabezpieczenia na poziomie wiersza, oto jak zawsze to robię z powyższym schematem zabezpieczeń:
-
Zawsze implementuję zabezpieczenia na poziomie wiersza jako serię widoków, które otaczają każdą tabelę i porównują tożsamość użytkownika (zwykle za pomocą Suser_Sname() lub jednego z innych) z listą zabezpieczeń wyprowadzoną z kodu zabezpieczającego w samym wierszu. To są widoki bezpieczeństwa.
-
Utwórz nowy schemat o nazwie [wiersze], przyznaj jego właścicielowi dostęp do schematu [dane] i do niczego więcej. Umieść wszystkie widoki bezpieczeństwa w tym schemacie.
-
Odbierz dostęp właściciela [exec] do schematu [data] i zamiast tego przyznaj mu dostęp do danych do schematu [wiersze].
Gotowe. Teraz zabezpieczenia na poziomie wiersza zostały zaimplementowane przez przejrzyste wsunięcie go między sProcs a tabele.
Wreszcie, oto przechowywana procedura, której używam, aby przypomnieć sobie, jak wiele z tych niejasnych elementów bezpieczeństwa działa i współdziała z samym sobą (ups, poprawiona wersja kodu ):
CREATE proc [TestCnxOnly].[spShowProc_Security_NoEX] as
--no "With Execute as Owner" for this version
--create User [UserNoLogin] without login
--Grant connect on database :: TestSecurity to Guest
--alter database TestSecurity set trustworthy on
--Show current user context:
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (sproc)]
, suser_sname() as sname
, system_user as system_
--Execute As Login = 'UserNoLogin'
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (after exec as)]
, suser_sname() as sname
, system_user as system_
EXEC('select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (in Exec(sql))]
, suser_sname() as sname
, system_user as system_')
EXEC sp_ExecuteSQL N'select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (in sp_Executesql)]
, suser_sname() as sname
, system_user as system_'
--Revert
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (aftr revert)]
, suser_sname() as sname
, system_user as system_
[EDIT:poprawiona wersja kodu)