Temo que sua descrição ou sua concepção de Encadeamento de Propriedade não seja clara, então deixe-me começar com isso:
"Ownership Chaining" simplesmente se refere ao fato de que, ao executar um procedimento armazenado (ou exibição) no SQL Server, o lote atualmente em execução adquire temporariamente os direitos/permissões do proprietário do sProc (ou do proprietário do esquema do sProc) enquanto executa esse código SQL. Portanto, no caso de um sProc, o usuário não pode usar esses privs para fazer qualquer coisa que o código sProc não implemente para eles. Observe especialmente que ele nunca adquire a Identidade do Proprietário, apenas seus direitos, temporariamente (no entanto, EXECUTE AS... faz isso).
Portanto, a abordagem típica para aproveitar isso para segurança é:
-
Coloque todas as Data Tables (e todas as Views que não sejam de segurança também) em seu próprio Schema, vamos chamá-lo de [data] (embora normalmente [dbo] seja usado porque já está lá e é muito privilegiado para o esquema do usuário). Certifique-se de que nenhum usuário, esquema ou proprietário existente tenha acesso a esse esquema [dados].
-
Crie um esquema chamado [exec] para todos os sProcs (e/ou possivelmente quaisquer exibições de segurança). Certifique-se de que o proprietário desse esquema tenha acesso ao esquema [data] (isso é fácil se você tornar dbo o proprietário desse esquema).
-
Crie um novo db-Role chamado "Users" e dê a ele acesso EXECUTE ao esquema [exec]. Agora adicione todos os usuários a esta função. Certifique-se de que seus usuários tenham apenas direitos de conexão e não tenham acesso concedido a nenhum outro esquema, incluindo [dbo].
Agora seus usuários podem acessar os dados apenas executando o sProcs em [exec]. Eles não podem acessar nenhum outro dado ou executar nenhum outro objeto.
Não tenho certeza se isso responde à sua pergunta (porque eu não tinha certeza de qual era exatamente a pergunta), então sinta-se à vontade para me redirecionar.
Quanto à segurança em nível de linha, aqui está como sempre faço isso com o esquema de segurança acima:
-
Eu sempre implemento segurança em nível de linha como uma série de Views que encapsulam todas as tabelas e comparam a identidade do usuário (geralmente com Suser_Sname() ou um dos outros) a uma lista de segurança codificada de um código de segurança na própria linha. Estas são as Visualizações de Segurança.
-
Crie um novo esquema chamado [rows], dê ao seu proprietário acesso ao esquema [data] e nada mais. Coloque todas as Security-Views neste esquema.
-
Revogue o acesso do proprietário [exec] ao esquema [data] e, em vez disso, conceda acesso de dados ao esquema [rows].
Feito. Agora, a segurança em nível de linha foi implementada deslizando-a de forma transparente entre os sProcs e as tabelas.
Finalmente, aqui está uma procura armazenada que eu uso para me ajudar a lembrar o quanto desse material de segurança obscuro funciona e interage com ele mesmo (ops, versão corrigida do código ):
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:versão corrigida do código)