Novo curso: Como proteger seus dados com Always Encrypted

Depois de uma semana ministrando um treinamento em Minas Gerais, as tão merecidas férias chegaram e com elas uma novidade: o lançamento do meu mini-curso sobre Always Encrypted no DevMedia!

Os leitores que nos acompanharam no ano passado sabem que venho falando sobre esta feature do SQL Server 2016 durante algum tempo. Aproveitando o embalo e a oportunidade, gravei para o site DevMedia um curso dinâmico com 13 módulos sobre Always Encrypted. Neste curso eu abordo alguns tópicos como:

  • Criação e armazenamento de certificados;
  • Criação de chaves criptográficas;
  • Criptografia de conteúdo usando Always Encrypted;
  • Implantação do Always Encrypted com separação de papéis;
  • Limitações, restrições e impactos do Always Encrypted; e
  • Muito mais. =]

Se o assunto te interessa, veja o primeiro módulo gratuitamente neste link [1]. Caso queira ver o conteúdo programático completo deste curso, acesse este outro link [2]. E, claro, deixe suas impressões e seus feedbacks nos comentários.

[]’s

LINKS

[1] http://www.devmedia.com.br/articles/viewaula.asp?idcomp=37767&topico=4156

[2] http://www.devmedia.com.br/curso/sql-server-como-proteger-seus-dados-com-always-encrypted/1931

Anúncios

Encontro SQL Server DF XXXIV – Material

Dia 12/07/2016 aconteceu mais um encontro do grupo SQLServerDF! Neste 34º encontro, falei um pouco a nova feature do SQL Server 2016: Always Encrypted.

Titulo

Apesar de um imprevisto com uma VM ter atrapalhado algumas demos, consegui mostrar o comportamento deste recurso tanto em memória como na rede. Isso é sempre divertido!

Agradeço a presença de todos e todo o feedback que recebi!

Segue o link com o material da apresentação, divirta-se!

https://drive.google.com/folderview?id=0B2dIfMDfAh7JQWlaZHBOSW8yczQ&usp=sharing

 

Encontro SQL Server DF XXXIV

Depois de um longo e tenebroso inverno, um post breve para avisar sobre o trigésimo quarto encontro do grupo SQL Server DF, o Local Chapter de Brasília, um dos mais (se não o mais) ativos do Brasil.

Dia 29/06/2016, tivemos o encontro de número 33 com uma excelente apresentação do Rodrigo Gomes (blog|twitter) intitulada “SQL Server CPU Foundations”. Esta sessão, que ele também realizou no SQL Saturday #512 no Rio de Janeiro, entrega de uma forma simples e clara algumas definições e diferentes métricas acerca do tema CPU. Recomendo à todos que tenham a oportunidade.

O evento que acontecerá dia 12/07/2016 é a edição de número 34 e eu estarei lá falando um pouco sobre Always Encrypted. Veremos como funciona esta nova feature do SQL Server 2016 e implantaremos ela simulando um ambiente real de cliente/servidor. Também pretendo mostrar como os novos cmdlets de Always Encrypted da atualização de Julho do SSMS facilitaram o trabalho na hora da criação das chaves. Ainda iremos ver como se comportam os dados criptografados tanto na rede como em memória.

Quando e onde será?

  • Data e Hora: 12/07/2016, das 18:30 às 20:30;
  • Local: Xperts Training Center (SHIS QI 15, Área Especial Subsolo, Conjunto 8/9, Próximo ao Hospital Brasília).

Demais detalhes podem ser encontrados no anúncio do encontro no blog do Luti.

Espero vocês lá!

Como verificar o HASH de um arquivo?

Após o lançamento do último patch de segurança nesta terça-feira (14/07/2015) que foi descrito no Security Bulletin MS15-058 [1] e no KB #3065718 [2], muita gente – eu inclusive – correu atrás de mais informações sobre o hotfix em blogs confiáveis. Em casos de atualizações em geral, costumo verificar alguns blogs do Aaron Bertrand [3][4] (twitter) que sempre comenta sobre o assunto. Sobre este patch em específico, o post dele no SQL Sentry contém um quadro que facilitou bastante identificar qual arquivo baixar de acordo com sua versão.

Após verificar as repercussões do patch, o próximo passo é baixar o arquivo adequado contendo o hotfix e aplicá-lo no ambiente de desenvolvimento. Certo? Ainda não. Como você pode garantir que o arquivo que baixou é realmente o mesmo arquivo disponibilizado pela Microsoft? Quem garante que você não está sendo vítima de um ataque de clickjacking e acabou baixando um malware? E se baixou o arquivo de uma outra fonte que não a Microsoft? Para isso utiliza-se o HASH de um arquivo.

A ideia de um HASH é criar uma forma única de identificação de um arquivo como uma impressão digital de uma pessoa. Diversos algoritmos estão disponíveis para a criação de HASHES. Um dos algoritmos mais famosos é o MD5, porem este já foi quebrado tem alguns anos. Atualmente utiliza-se mais a família de algoritmos SHA-2 (SHA-224, SHA-256, SHA-384 e SHA-512) e, apesar de colisões diversas terem sido identificadas no SHA-1, o algoritmo SHA 1 ainda é bastante utilizado em protocolos de segurança como SSL e IPSec.

“Mas por que você está falando sobre HASHES? O que isso tem a ver com o patch?” Se você olhar no final do KB na seção “File hash information”, existem 2 HASHES (SHA-1 e SHA-256) para cada arquivo disponibilizado. Então, após baixar o arquivo, basta verificar o HASH do arquivo para garantir que este é o arquivo verdadeiro.

GERANDO O HASH DE UM ARQUIVO

Para gerar o HASH desses arquivos, você pode usar o antigo File Checksum Integrity Verifier (FCIV) [5]. O problema do FCIV é sua limitação: ele gera apenas os HASHES MD5 e SHA-1. Como eu disse, ele é bem antigo. No entanto, só de verificar um dos HASHES do arquivo, você garante uma camada adicional de segurança.

Utilizar o FCIV é bem direto. Supondo que quero verificar o SHA-1 do arquivo “D:\SQLServer2008R2-KB3045314-x64.exe”, basta eu executar o comando abaixo e voilà.

Não importa o que digam, você ainda faz o seu trabalho FCIV!

Não importa o que digam, você ainda faz o seu trabalho FCIV!

Outra forma de gerar os HASHES é através do comando Get-FileHash [6] do PowerShell (testado na versão 4.0 em diante). Este método já está atualizado com o algoritmo SHA-256. Para gerarmos os HASHES do mesmo arquivo, basta executarmos os seguintes comandos e verificar com os fornecidos pela Microsoft.

Quanta elegância esse PoSh!

Quanta elegância esse PoSh!

Agora você executar os arquivos tendo certeza de que são verdadeiros! Bom patching!

REFERÊNCIAS / LINKS

[1] Microsoft Security Bulletin MS15-058 – Important (https://technet.microsoft.com/en-us/library/security/MS15-058)
[2] MS15-058: Vulnerabilities in SQL Server could allow remote code execution: July 14, 2015 (https://support.microsoft.com/en-us/kb/3065718)
[3] SQLblog.com (http://sqlblog.com/blogs/aaron_bertrand/default.aspx)
[4] Blogs.SqlSentry.com (http://blogs.sqlsentry.com/author/AaronBertrand/)
[5] File Checksum Integrity Verifier utility (https://support.microsoft.com/en-us/kb/841290)
[6] Get-FileHash (https://technet.microsoft.com/en-us/library/dn520872.aspx)

SQL Injection, como o DBA pode se proteger?

Depois da empolgante (e até um pouco aterrorizante) palestra “Invadindo o SQL Server? DBA Vs. Hacker” apresentada pelo Luan Moreno (blog|twitter) e pelo Lenon Leite (twitter) no XIX encontro do grupo SQLServerDF, me senti quase obrigado a falar sobre segurança. Logo, neste post irei falar sobre algumas dicas e formas para o DBA se prevenir de um possível ataque através de uma SQL Injection.

No entanto, antes de qualquer coisa, o que é SQL Injection? SQL Injection, ou Injeção de SQL, é uma técnica de inserção de código malicioso que explora vulnerabilidades na segurança da aplicação ou da base de dados. Geralmente esses ataques ocorrem quando as entradas de dados dos usuários não são devidamente tratadas pela aplicação ou quando a consulta é construída dinamicamente, mas é claro que os ataques não são limitados apenas a essas formas.

SQL dinâmico é um código ou comando que é executado dinamicamente (Duh?!). Em outras palavras, é quando se concatena linhas de código com entradas do usuário para montar um comando SQL “na hora”, ou, dinamicamente. Codificar utilizando o SQL dinâmico traz grande flexibilidade e, quando bem aplicado, pode gerar planos de execução mais eficientes. Mas, como nem tudo na vida são flores, a manutenção de códigos com SQL dinâmico é bem mais complicada e esse código, quando utilizado indevidamente, pode gerar brechas enormes na segurança do banco de dados e uma baixíssima taxa de reutilização de planos de execução. Sem prolongar mais esta introdução, vamos demonstrar como pode acontecer um ataque por SQL Injection.

Vamos supor que uma locadora de filmes empresa que oferece serviços de TV pela internet tem um sistema de busca de filmes no seu catálogo. Nesse sistema o usuário pode procurar o filme por título, diretor ou gênero. Agora, vamos supor que esta busca é feita por uma stored procedure como a abaixo.

CREATE PROCEDURE [dbo].[RetornaFilme](
	@Titulo  VARCHAR(MAX) = NULL,
	@Diretor VARCHAR(MAX) = NULL,
	@Genero  VARCHAR(MAX) = NULL)
AS

DECLARE @sql VARCHAR(MAX);

SET @sql =      'SELECT [Titulo],[Diretor],[Genero] '+
                'FROM [dbo].[Filmes] '+
                'WHERE (1=1) ';

IF(@Titulo IS NOT NULL)
SET @sql = @sql + 'AND [Titulo] LIKE '''+@Titulo+'''';

IF(@Diretor IS NOT NULL)
SET @sql = @sql + 'AND [Diretor] LIKE '''+@Diretor+'''';

IF(@Genero IS NOT NULL)
SET @sql = @sql + 'AND [Genero] LIKE '''+@Genero+'''';

EXEC(@sql)
GO

Esse tipo de consulta acaba sendo bem comum quando utilizamos filtros dinâmicos. Vale ressaltar que esta SP não segue boas práticas de programação. Em breve ficarão evidentes os motivos.

Então, supondo que estejamos atrás de filmes de aventura, basta executarmos nossa busca.

RetornaFilme_01

Tudo dentro do esperado! Agora que vemos que ela funciona, que tal vermos se aquele filme Rock ‘n’ Rolla está no catálogo?

RetornaFilme_02

Com esta mensagem de erro, evidenciamos uma brecha na segurança em nossa SP. “Mas… o que deu errado?” Um dos problemas aqui é o tratamento (ou falta de) da entrada do usuário. Se imprimirmos o comando que está sendo executado, temos o seguinte.

SELECT [Titulo],[Diretor],[Genero]
FROM [dbo].[Filmes]
WHERE (1=1) AND [Titulo] LIKE 'Rock 'n' Rolla';

Aqui fica claro que a letra “n” ficou fora da string. Isso já foi o suficiente para gerar um erro que demonstra que esta SP não trata nomes que contenham aspas simples. Através deste tipo brechas que hackers vão inserir trechos de código malicioso. Eis um exemplo de código malicioso para obter mais informação que o esperado.

RetornaFilme_03

“O que é esse result… Essas são as tabelas no banco e suas colunas?!” Exatamente. Uma relação de todas as tabelas criadas e suas colunas. Depois de algumas tentativas e um pouco de conhecimento em banco de dados – e pode ter certeza que hackers tem tanto tempo quanto o google à disposição deles – um usuário malicioso poderia entrar com esse parâmetro e voilà. Agora ele já sabe o que tem dentro da sua base de dados. Agora basta ajustar novamente o parâmetro e…

RetornaFilme_04

Neste momento o sorriso está estampado na cara do hacker, afinal de contas, agora ele tem todos os dados de todos os usuários cadastrados nesta empresa. Quanto será que isso deve valer para a empresa concorrente? Bastante, imagino. Mas vamos ver o que ocorreu com essa SP para que houvesse esta brecha. Imprimindo o parâmetro “@sql” para este último caso temos:

SELECT [Titulo],[Diretor],[Genero]
FROM [dbo].[Filmes] WHERE (1=1) AND [Titulo] LIKE 'a'
UNION
SELECT nome,email,conta_bancaria
FROM Usuario --'

Pelo fato da execução do código ser baseada na concatenação de strings, observa-se que o trecho de código malicioso fecha a busca por título – com a’ – e então utiliza o operador UNION para trazer informações adicionais que neste caso são bem sensíveis. Depois ele utiliza o comentário de linha “- -“ para anular qualquer código posterior.

Outro exemplo mais agressivo de ataque é quando o código malicioso tenta alterar ou apagar algo dentro da sua base ou até em seu servidor. O objetivo pode ser apagar o catálogo de filmes, os registros dos usuários ou só dificultar a sua vida como DBA.

EXEC [dbo].[RetornaFilme] @Titulo = 'a''; DROP TABLE Filmes; --';

Mas é claro que sempre é possível piorar. Então, aviso antes mesmo de colocar o comando abaixo: Não execute o código abaixo em lugar nenhum (Não, nem mesmo assim). A SP xp_cmdshell é capaz de executar comandos em shell como se estivesse no command prompt do Windows. Dependendo do nível de permissão do usuário que executa esta SP, ele pode fazer o que quiser com a máquina. Então, depois de avisar que você não deve brincar com essa SP, eis a possível injeção de SQL.

EXEC [dbo].[RetornaFilme]
@Titulo = 'a''; EXEC master.dbo.xp_cmdshell ''format d:''--';

Calma. A SP xp_cmdshell é desativada por padrão a partir do SQL Server 2005, mas se o invasor conseguir privilégios de sysadmin ele pode mudar isso (Aí sim, já era). No entanto, apesar do potencial destrutivo desta SP, é comum encontrá-la ativada para usos administrativos – o que também não é considerado uma boa prática de segurança.

Como vimos, a utilização de SQL dinâmico pode gerar uma brecha enorme na segurança e nosso objetivo neste artigo é saber como reduzir essa superfície de ataque ao máximo para evitarmos uma injeção de SQL. Então vejamos algumas medidas que podemos tomar!

1.Dimensione e determine as variáveis apenas de acordo com o necessário. Variáveis fortemente tipadas diminuem a liberdade do invasor ao inserir código malicioso. No nosso caso, o tipo VARCHAR(MAX) dá liberdade total para o ataque.

2.Valide toda e qualquer entrada do usuário. Aproveitando até os tipos bem definidos, utilize funções de verificação. Se o tipo deve ser numérico, use ISNUMERIC(). Se for data, ISDATE(), e assim por diante. Em caso de strings, utilize REPLACE() para substituir aspas simples por aspas duplas.

3.Utilize prints para debugar o código. Ao acrescentar uma forma de debugar o resultado da concatenação de strings, vemos com muito mais clareza possíveis brechas no código. Além disso, fica muito mais fácil realizar uma manutenção!

4.Dê o mínimo de permissão ao usuário que executar a SP. Aqui é mais um controle de danos. Pois, por mais que o invasor consiga entrar com algum código malicioso, ele não conseguirá fazer muito estrago.

Então se ajustarmos nossa consulta de acordo com essas premissas, teríamos algo como o código abaixo.

CREATE PROCEDURE [dbo].[RetornaFilme](
	@Titulo  VARCHAR(100) = NULL,
	@Diretor VARCHAR(50)  = NULL,
	@Genero  VARCHAR(20)  = NULL,
	@Debug   BIT          = 1)
AS

DECLARE @sql VARCHAR(MAX);

SET @sql =      'SELECT [Titulo],[Diretor],[Genero] '+
                'FROM [dbo].[Filmes] '+
                'WHERE (1=1) ';

IF(@Titulo IS NOT NULL)
SET @sql = @sql + 'AND [Titulo] LIKE '''+REPLACE(@Titulo,'''','''''')+'''';

IF(@Diretor IS NOT NULL)
SET @sql = @sql + 'AND [Diretor] LIKE '''+REPLACE(@Diretor,'''','''''')+'''';

IF(@Genero IS NOT NULL)
SET @sql = @sql + 'AND [Genero] LIKE '''+REPLACE(@Genero,'''','''''')+'''';

IF(@Debug = 1) PRINT @sql;
EXEC(@sql) AS USER = 'usuario_acesso_minimo';
GO

Desta forma diminuímos consideravelmente a superfície de ataque do invasor. No entanto, ainda estamos gerando uma baixíssima taxa de reutilização dos planos de execução. Afinal de contas, somente se os parâmetros usados forem idênticos o plano de execução poderá ser reutilizado. Então vamos para a última – e talvez mais importante – dica:

1.Sempre que possível, utilize sp_executesql ao invés de EXEC(). A stored procedure sp_executesql, por ser parametrizada, facilita a reutilização dos planos de execução e, como iremos ver, acaba blindando as entradas do usuário dentro das variáveis.

Reformulando nossa consulta para utilizar a sp_executesql, temos o código a seguir.

CREATE PROCEDURE [dbo].[RetornaFilme](
	@Titulo  VARCHAR(100) = NULL,
	@Diretor VARCHAR(50)  = NULL,
	@Genero  VARCHAR(20)  = NULL,
	@Debug   BIT          = 1)
AS

DECLARE @sql NVARCHAR(MAX);
DECLARE @params NVARCHAR(MAX);

SET @sql =  'SELECT [Titulo],[Diretor],[Genero] '+
            'FROM [dbo].[Filmes] '+
            'WHERE (1=1) ';

SET @params = '@Titulo  VARCHAR(100) = NULL,'+
              '@Diretor VARCHAR(50)  = NULL,'+
              '@Genero  VARCHAR(20)  = NULL';

IF(@Titulo IS NOT NULL)
SET @sql = @sql + 'AND [Titulo] LIKE @Titulo ';

IF(@Diretor IS NOT NULL)
SET @sql = @sql + 'AND [Diretor] LIKE @Diretor ';

IF(@Genero IS NOT NULL)
SET @sql = @sql + 'AND [Genero] LIKE @Genero ';

IF(@Debug = 1) PRINT @sql;
EXEC sp_executesql @sql, @params, @Titulo, @Diretor, @Genero
GO

Pronto! Além de termos um código mais limpo e simples, nossos planos de execução serão reutilizados com muito mais frequência graças à parametrização que agora é possível!

Neste artigo, vimos como o DBA pode se proteger melhor de uma SQL Injection e digo “se proteger melhor” pois, é muito difícil – se não impossível – se proteger 100% contra esse tipo de ataque. No entanto, diminuímos a superfície de ataque de possíveis invasores e ainda parametrizamos nossa consulta para uma maior reutilização dos planos de execução. Mas, como esse tópico me deixou com mais vontade de ler e estudar sobre o assunto, deixo aqui alguns lugares para que você continue sua leitura.

1.Consultas parametrizadas, ISNULL e SQL dinâmica, um post do Gustavo Maia Aguiar que explora um pouco mais sobre implementações de consultas parametrizadas e seus efeitos nos planos de execução.

2.The Curse and Blessings of Dynamic SQL, um artigo excelente do Erland Sommarskog que menciona SQL Injection, boas práticas quando utilizar SQL dinâmico e casos comuns de quando não se utilizar SQL dinâmico.

3.Inside Microsoft SQL Server 2008: T-SQL Programming, livro de Itzik Ben-Gan e companhia que considero leitura obrigatória para qualquer DBA/AD/Desenvolvedor que trabalhe com T-SQL.