SQL Server – Evitando consultas em determinadas colunas com o Column Level Security (CLS)
Tempo de Leitura: 6minutos
Olá pessoas!
Nesse artigo eu gostaria de demonstrar um recurso bem antigo (disponível desde o SQL Server 2005 – ou antes) e que pouca gente utiliza ou conhece que existe, que é o Column Level Security (CLS) ou Segurança a nível de coluna. Diferente do Row Level Security, onde o usuário visualiza todas as colunas mas apenas algumas linhas, no CLS a restrição é feita em determinadas colunas em que o usuário terá ou não acesso para visualizar.
Esse recurso também está disponível no Azure SQL Datawarehouse, mas, até o momento em que estou escrevendo esse artigo, não está disponível para o Azure SQL Database.
Um exemplo clássico para demonstrar o uso desse recurso é uma tabela de Funcionarios, em uma base de RH, por exemplo:
Transact-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CREATETABLEdbo.Funcionario (
CodigoINTIDENTITY(1,1)NOTNULLPRIMARYKEYCLUSTERED,
NomeVARCHAR(50)NOTNULL,
CargoVARCHAR(50)NOTNULL,
SalarioNUMERIC(18,2)NOTNULL
)
INSERTINTOdbo.Funcionario
(
Nome,
Cargo,
Salario
)
VALUES
('João','DBA JR',7259.87),
('José','DBA PL',11022.91),
('Matheus','DBA SR',18751.22)
Nesse cenário, um DBA mais despreocupado com a segurança do ambiente daria acesso de leitura (SELECT) nessa tabela para o usuário solicitante, e este conseguiria consultar todos os dados da tabela:
Transact-SQL
1
2
3
4
5
6
GRANTSELECTONdbo.FuncionarioTO[usrChato]
-- Ou se você for um DBA que não tá nem aí com a segurança mesmo
ALTERROLE[db_datareader]ADDMEMBER[usrChato]
GRANTSELECTTO[usrChato]
GRANTSELECTONSCHEMA::dboTO[usrChato]
Ao tentar realizar a consulta na tabela, conseguimos olhar todas as linhas e colunas:
Para os DBA’s mais preocupados com segurança e privacidade dos dados, um recurso que eu costumo ver com frequência sendo utilizado é a utilização de views para limitar as colunas que determinados usuários terão acesso de visualizar.
Ou seja, caso eu queira que o nosso usrChato tenha acesso a todas as colunas da tabela Funcionario, menos a de Salario, eu posso criar uma view sem essa coluna e dar acesso de select na view para esse usuário:
E com isso, caso o usuário tente acessar diretamente a tabela de Funcionario, irá tomar uma mensagem de erro de falta de permissão:
Enquanto ele terá acesso na view, que possui todos os campos, menos o Salario:
E agora, sempre que eu tiver um usuário que precise visualizar todas as colunas dessa tabela, menos o salário, eu libero acesso de SELECT nessa view (ou gerencio o acesso através de roles).
Mas e quando eu tenho vários usuários, com diferentes necessidades de controle de quais colunas eles vão acessar? Vou criar um monte de views no meu ambiente para atender a cada necessidade ?
Utilizando o Column Level Security (CLS) para restringir colunas
Clique para visualizar o conteúdo
Disponível desde a versão 2005 do SQL Server (provavelmente até antes), existe um recurso chamado Column Level Security (CLS), também conhecido como Column Level Permission, que permite a definir em quais colunas determinada permissão será aplicada para o usuário.
A grande vantagem dessa abordagem, é que de forma alguma o usuário terá acesso à essa coluna, mesmo que sejam criadas views consultando a tabela em questão e ele tenha acesso nessa view (neste caso, teremos que utilizar o DENY). Além disso, você evita ficar criando vários objetos e views para atender a necessidades de segurança, exclusivamente.
Entretanto, uma grande desvantagem dessa abordagem, é que o usuário precisará conhecer muito bem a estrutura da tabela e as colunas específicas que ele precisará consultar, já que um SELECT * não vai funcionar mais.
No exemplo desse artigo, vou definir que o usrChato só tenha permissão de visualizar as colunas Codigo, Nome e Cargo na tabela Funcionario:
Msg 230, Level 14, State 1, Line 4
The SELECT permission was denied on the column ‘Salario’ of the object ‘Funcionario’, database ‘master’, schema ‘dbo’.
Ou ao tentar realizar o famoso SELECT * FROM:
Transact-SQL
1
2
3
4
5
6
7
8
EXECASUSER='usrChato'
GO
SELECT*FROMdbo.Funcionario
GO
REVERT
GO
Msg 230, Level 14, State 1, Line 4
The SELECT permission was denied on the column ‘Salario’ of the object ‘Funcionario’, database ‘master’, schema ‘dbo’.
E se eu criar uma view que tenha essa coluna? Será que o usuário conseguirá visualizar os dados, mesmo que ele não tenha permissão na Tabela ?
Ouch!! O usuário conseguiu visualizar o salário!! E agora?
Bom, para resolver isso precisamos aplicar um comando de DENY na coluna de salário NA VIEW (na tabela original não adianta, pois o usuário tem acesso full na view):
Transact-SQL
1
DENYSELECTONdbo.vwFuncionario_Completo(Salario)TO[usrChato]-- poderia ser public aqui, caso queira que ninguém acesse
Msg 230, Level 14, State 1, Line 4
The SELECT permission was denied on the column ‘Salario’ of the object ‘vwFuncionario_Completo’, database ‘master’, schema ‘dbo’.
É importante observar que é possível utilizar o Column Level Security (CLS) (também conhecido como Column Level Permission) em conjunto com as seguintes permissões:
SELECT
UPDATE
REFERENCES
Esse recurso não é exclusividade apenas de tabelas. Ele é compatível com views também, e funciona da mesma forma.
Como identificar as permissões a nível de coluna
Clique para visualizar o conteúdo
Caso você opte por começar a utilizar esse recurso, é importante saber como identificar em quais colunas determinado usuário tem acesso. Uma das formas de visualizar isso é utilizando a interface do SSMS (SQL Server Management Studio).
Abre o database onde está sua tabela, expanda a pasta “Security” e depois “Users”, clique com o botão direito do mouse e clique na opção “Properties”:
Na janela que abriu, clique na opção “Securables”, selecione a tabela que deseja visualizar, clique na aba “Explicit” para visualizar as permissões e role a lista até encontrar a permissão Select. Ao clicar sobre esse item, verá que o botão “Columns Permissions” agora está habilitado.
Para visualizar as colunas, clique na aba “Effective”
E caso queira ver mais detalhes sobre as permissões das colunas, clique no botão “Columns Permissions”
Uma outra forma de identificar as permissões a nível de coluna é através de query no banco:
Aqui chegamos a um ponto de vista muito pessoal.. Eu, particularmente, prefiro gerenciar as permissões através de views, pois a gestão é mais simples do que ter uma tabela ou view onde cada usuário acessa de um jeito. Como já havia comentado nesse artigo, utilizando a permissão a nível de coluna, evitamos a criação de vários objetos no banco apenas para fins de segurança e privacidade dos dados, mas ao mesmo tempo, o usuário precisará conhecer muito bem a estrutura da tabela e as colunas específicas que ele precisará consultar, já que um SELECT * não vai funcionar mais.
Eu acredito que as 2 soluções atendem muito bem ao que se refere restringir o acesso de usuários não autorizados à colunas sensíveis, cabe à equipe de banco escolher qual método ela vai se habituar melhor a trabalhar.
Caso você esteja utilizando a versão 2016 ou superior, pode também utilizar o recurso de Dynamic Data Masking para mascarar a saída de colunas que tenham dados sensíveis.
É isso aí, pessoal!
Espero que tenham gostado dessa dica e até a próxima!