Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

SQL Server:Como esquemas de permissão?


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 é:

  1. 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].

  2. 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).

  3. 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:

  1. 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.

  2. 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.

  3. 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)