Clique no banner para conhecer e adquirir o meu treinamento de Bancos de Dados no Azure

SQL Server 2016 – Mascaramento de dados com o Dynamic Data Masking (DDM)

Post Views 9,071 views
Esse post é a parte 3 de 5 da série Data Protection
Reading time 7 minutes

Olá pessoal,
Tudo certo?

Introduction

Neste post eu gostaria de demonstrar um recurso bem interessante do SQL Server, disponível a partir da versão 2016, que é o Dynamic Data Masking (DDM) e que nos permite mascarar e ocultar informações sensíveis de determinados usuários de forma rápida, prática.

Diferente dos recursos de criptografia do SQL Server Transparent Data Encryption (TDE) e Always Encrypted, que criptografam fisicamente os dados e arquivos do banco (até os backups e backups de log são gerados já criptografados, e os arquivos MDF, LDF e NDF também são criptografados), o mascaramento de dados Dynamic Data Masking não criptografa realmente os dados, apenas aplica uma máscara nas consultas realizadas no banco de dados para usuários não-privilegiados.

Para aplicar o mascaramento de dados, você deve executar um comando de ALTER na coluna e que deseja aplicar a máscara (o mascaramento dos dados é a nível de coluna) ou pode adicionar essa definição no CREATE da tabela.

Limitações e restrições

Não é possível definir uma regra de mascaramento para os seguintes tipos de coluna:

  • Colunas criptografadas (Always Encrypted)
  • FILESTREAM
  • Uma máscara não pode ser configurada em uma coluna computada, mas se a coluna computada depender de uma coluna com uma MÁSCARA, ela retornará dados mascarados.
  • Uma coluna com mascaramento de dados não pode ser uma chave para um índice FULLTEXT.

Tipos de máscaras

No Dynamic Data Masking, você pode definir como os dados serão mascarados utilizando algumas funções de mascaramento de dados, que serão detalhadas abaixo:

FunçãoDescriçãoExemplos
DefaultMascaramento de acordo com os tipos de dados dos campos designados.

Para os tipos de dados string, os valores originais serão substituídos pelos caracteres XXXX. É aplicável aos tipos de dados char, nchar, varchar, nvarchar, text e ntext

Para os tipos de dados numéricos, o valor original será substituído pelo número 0 (zero). É aplicável aos tipos de dados bigint, bit, decimal, int, money, numeric, smallint, smallmoney, tinyint, float e real.

Para os tipos de dados data e hora, será utilizada a data 1900-01-01 00:00:00.0000000. É aplicável aos tipos de dados date, datetime2, datetime, datetimeoffset, smalldatetime e time.

Para os tipos de dados binary, o valor original será substituído por um único byte de valor ASCII 0.
É aplicável aos tipos de dados binary, varbinary e image.
ALTER TABLE dbo.DDM ALTER COLUMN Nome ADD MASKED WITH(FUNCTION = 'default()')
EmailO método de mascaramento que expõe a primeira letra de um endereço de email e o sufixo constante ".com", na forma de um endereço de email

Ex: [email protected] será mascarado como [email protected]
ALTER TABLE dbo.DDM ALTER COLUMN Email ADD MASKED WITH(FUNCTION = 'email()')
RandomA função de mascaramento random(numero_inicial, numero_final) permite substituir um valor numérico por um número aleatório gerado a partir de um intervalo pré-definido.

Colunas que possuem tipos de dados que aceitam valores decimais podem aceitar intervalos na forma de números decimais ou inteiros na função random(). Caso o intervalo seja composto por 2 números inteiros em uma coluna que aceita valores decimais, os valores aleatórios gerados terão casas decimais também com valores aleatórios (veja os exemplos).
ALTER TABLE dbo.DDM ALTER COLUMN Salario ADD MASKED WITH(FUNCTION = 'random(0.5, 0.99)')

ALTER TABLE dbo.DDM ALTER COLUMN Peso ADD MASKED WITH(FUNCTION = 'random(70, 120)')
PartialA função de mascaramento partial(prefixo, preenchimento, sufixo) mostra as primeiras N letras (N = prefixo) e últimas N letras (N = sufixo) e adiciona uma cadeia S de caracteres de preenchimento personalizada no meio (S = preenchimento).

Observação: se o valor original for muito curto para completar a máscara inteira, parte do prefixo ou sufixo não será exposta, ou seja, caso a string seja "Dirceu" e a função de mascaramento seja partial(4, "XXXX", 4), a string será mascarada como "XXXX", não respeitando os valores que prefixo e sufixo, que não serão mostrados.
ALTER TABLE dbo.DDM ALTER COLUMN CPF ADD MASKED WITH(FUNCTION = 'partial(0, "XXXXXXXXX", 2)')

ALTER TABLE dbo.DDM ALTER COLUMN Cargo ADD MASKED WITH(FUNCTION = 'partial(3, "XXXXXXXXXXX", 4)')

Exemplos e demonstrações

Para demonstrar melhor as funcionalidades e funções do Dynamic Data Masking, preparei um exemplo abaixo, demonstrando como criar uma tabela com alguns campos já mascarados, depois vamos visualizar esses campos com a máscara.

Vou alterar a tabela para mascarar mais colunas, visualizar os dados mascarados (agora com todas as colunas) e depois visualizar 5x o resultado para observar o comportamento da função de mascaramento random() quando executada várias vezes.

Exemplo do Dynamic Data Masking

Visualizando os dados originais (com usuário sysadmin):

Visualizando os dados mascarados após a criação da tabela (com usuário comum):

Visualizando os dados mascarados após todas as alterações:

Segurança e Permissões

Para criar ou alterar uma tabela utilizando o Dynamic Data Masking, não é necessário nenhuma permissão especial, apenas as permissões tradicionais para criação/alteração de tabelas (CREATE TABLE e/ou ALTER).

Para adicionar, alterar ou remover a máscara de uma coluna, o usuário deve ter as permissões de ALTER ANY MASK e ALTER.

Os usuários com a permissão SELECT em uma tabela poderão visualizar os dados da tabela e as colunas mascaradas exibirão os dados mascarados. para que o usuário possa visualizar os dados originais, isto é, sem máscaras, ele deve possuir a permissão UNMASK (GRANT UNMASK TO [User]).

Além disso, a permissão CONTROL no banco de dados inclui as permissões ALTER ANY MASK e UNMASK, ou seja, usuários das roles db_owner ou sysadmin, podem visualizar os dados originais de colunas mascaradas.

Quais colunas estão mascaradas ?

Para identificar quais colunas do seu database estão mascaradas utilizando Dynamic Data Masking, basta executar a query abaixo:

Exemplo de retorno:

Quebrando o Dynamic Data Masking

Uma vez apresentados os recursos do Dynamic Data Masking, precisamos falar também que esse método não deve ser a única forma de garantir a segurança dos seus dados. Embora ele ajude a proteger informações sensíveis, ele possui algumas falhas que permitem que usuários não autorizados acessem essas informações utilizando técnicas de força bruta.

No exemplo acima, inseri um registro na tabela onde o salário era R$ 12.345,67. Utilizando a força bruta (ou tentativa e erro), podemos encontrar o valor aproximado desse salário (com paciência ou criando um algoritmo para isso, até o valor exato)

Exemplo 1 – Valor numérico:
Neste exemplo, vou demonstrar como é possível identificar valores numéricos mascarados a partir de simples SELECT’s na tabela. No exemplo abaixo, fiz apenas 6 consultas e já consegui descobrir um valor bem próximo do valor real. Caso eu quisesse descobrir o valor exato, bastavam mais algumas consultas para isso:

Quer descobrir o valor exato? Vamos utilizar um script simples para isso:

Resultado: salário do Joãozinho revelado!

Exemplo 2 – Texto
Aqui, vou demonstrar como retornar a string exata que estava mascarada utilizando uma tabela de caracteres e fazendo join letra a letra com essa tabela. Cada letra da string mascarada fará um join com a minha tabela de caracteres para descobrir qual o caractere original.

And that's it, folks!
Espero que tenham gostado desse post e até mais!