Quando a nossa aplicação lida com dados sigilosos, precisamos nos atentar em como ela armazena isso fisicamente. Se alguém não autorizado tem acesso à base de dados, ele poderá visualizar todos os dados que estão lá. Uma opção que temos é armazenar os dados criptografados, mas nesta situação, temos que nos preocupar como a chave de criptografia se quisermos reverter o valor para utilizá-lo novamente.
Imagine que o cliente faça uma compra no site, e depois que ele informa o cartão de crédito, queremos armazenar ele para melhor a experiência sua usuário, e assim, na próxima compra, o cartão já estará armazenado, não precisando informar novamente. Por mais que a aplicação não exponha diretamente o número do cartão de crédito em suas páginas/telas, se houver alguma vulnerabilidade, é possível ter acesso à tabela e, consequentemente, ao número de todos os cartões que estiverem lá.
O SQL Server 2016 possui um recurso chamado data mask, que como o próprio nome sugere, permite ofuscar a informação de uma determinada coluna para um determinado login, e por mais que se explore a vulnerabilidade, o SELECT sempre retornará o dado aplicando a mascará que você configurou. No script abaixo, alteramos a coluna CartaoDeCredito para exibir apenas os dois primeiros e os dois últimos números do cartão. Há ainda outras funções predefinidas, que retornam o valor padrão do tipo de dado da coluna, uma que substitui o endereço de e-mail por asteriscos, entre outras.
ALTER TABLE Cliente ALTER COLUMN CartaoDeCredito ADD MASKED WITH (FUNCTION = 'partial(2, "**-****-****-**", 2)') GO
Para o exemplo, criei um login limitado chamado WebUser, concedendo a permissão para realizar SELECT na tabela de clientes. Agora note que abaixo estamos utilizado ADO.NET para extrair o número do cartão de crédito para apresentar na tela. Quando utilizamos a string de conexão com acesso irrestrito, o cartão de crédito é exibido integralmente; se utilizarmos a string de conexão com o usuário WebUser, o cartão é apresentado com uma porção de asteriscos.
static void Main(string[] args) { const string conexao1 = "Data Source=.;Initial Catalog=DB;user id=WebUser;password=123"; const string conexao2 = "Data Source=.;Initial Catalog=DB;Integrated Security=True"; Exibir(conexao1); Exibir(conexao2); } private static void Exibir(string connString) { using (var conn = new SqlConnection(connString)) { using (var cmd = new SqlCommand("SELECT CartaoDeCredito FROM Cliente", conn)) { conn.Open(); using (var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) if (dr.Read()) Console.WriteLine(dr.GetString(0)); } } }
E o resultado é:
12-****-****-78
1234-5678-1234-5678