Em um artigo anterior mostrei a você como guardar senhas com segurança no SQL, hoje vamos avançar ainda mais no assunto, aprendendo como proteger ainda mais as credenciais de usuários salgando e apimentando senhas!

É difícil quebrar uma senha?

Apesar dos algoritmos padrão, como MD5, SHA, SHA2, etc… serem indicados quando queremos proteger uma informação, quebrar a segurança deles as vezes pode ser feito em questão de segundos…

Veja o exemplo a seguir: Esse hash (EAB2E06EAFEB391903483173F490BFA38E965488) foi gerado pelo algoritmo SHA para a senha (P4$$word).

Apesar da senha possuir os atributos de segurança que normalmente as empresas exigem (tamanho de 8 caracteres, letras maiúsculas e minúsculas, números e caracteres especiais), usando o site https://hashkiller.co.uk nós podemos decifra-la literalmente em segundos:

 

Nossa, é assim tão fácil? Dependendo das senhas escolhidas por seus usuários, sim, é assim fácil!

 

A pergunta que fica é como melhorar a segurança do armazenamento para que a criptografia não seja tão facilmente quebrada dependendo da senha do usuário.

 

Uma das respostas desse enigma é “salgar a senha”…

 

Salgando senhas – Sal fixo

Salgar uma senha consiste adicionar texto a informação original (no caso a senha), tornando-a mais complexa e longa, o que dificulta a quebra da segurança por atacantes e piratas cibernéticos.

 

Veja abaixo um exemplo de salgamento tradicional:

 

print '--------------------------------------------------'
print 'Salgamento tradicional'
print '--------------------------------------------------'
-- Adicionar informações ao dado a ser protegido, dificultando cracking
declare @senha varchar(100)			= 'P4$$word'
declare @sal varchar(300)			= ' "!@#$%&*()_+=/;:?|/<>][{}_-´`abcdefghijklmnopqrstuwxz1234567890áâàäéêèëíìïóôòöúûùüÁÂÀÉÊÈÍÎÌÏÓÔÒÚÛÙÜ'
declare @senha_e_sal varchar(300)	= @senha + @sal
print 'Senha ................: ' + @senha
print 'Sal . ................: ' + @sal
print 'Senha + sal...........: ' + @senha_e_sal
print 'Senha (sha)...........: ' + convert(varchar(300), hashbytes('sha', @senha), 2)
print 'Senha e sal (sha).....: ' + convert(varchar(300), hashbytes('sha', @senha_e_sal), 2)
print 'Senha e sal (sha2_512): ' + convert(varchar(300), hashbytes('sha2_512', @senha_e_sal), 2)
print ''
go

 

Na variável @sal temos uma sequência de caracteres que deixa a senha muito mais longa e complexa.

Enquanto que a senha original (P4$$word) gerava o hash (EAB2E06EAFEB391903483173F490BFA38E965488) que podia ser quebrado em segundos, a senha com sal gera o hash (86B167322324C9442208C038226BC0D9AB34D1EB) que não foi quebrado pelo site que usamos para testes:

Salgando senhas – Sal variável

Particularmente gosto de incluir no sal alguma informação variável, no caso de senhas, costumo incluir o nome ou ID do usuário a qual a senha pertence, criando algo que chamo de “sal variável” ou “salgamento dba-pro”.

 

No exemplo abaixo, uso o nome dos usuários como parte do sal (a parte variável) em adição a parte fixa (como fizemos no exemplo tradicional acima). Em geral o nome do usuário é uma informação imutável, ainda assim, adiciona grande complexidade na hora de um atacante tentar quebrar a senha.

 

print '--------------------------------------------------'
print 'Salgamento dba-pro: Sal variável + fixo'
print '--------------------------------------------------'
-- Adicionar "sal variável" para cada registro
declare @usuarios table (login varchar(300), senha varchar(300))
insert into @usuarios values ('joao', null)
insert into @usuarios values ('maria', null)
declare @senha varchar(100)	= 'P4$$word'
declare @sal varchar(300)   = ' "!@#$%&*()_+=/;:?|/<>][{}_-´`abcdefghijklmnopqrstuwxz1234567890áâàäéêèëíìïóôòöúûùüÁÂÀÉÊÈÍÎÌÏÓÔÒÚÛÙÜ'
select 
	login, 
	@senha as senha_dos_usuarios,
	@sal as sal_padrao,
	@senha + @sal as senha_e_sal,
	convert(varchar(300), hashbytes('sha2_512', @senha + @sal), 2) as hash_senha_e_sal_padrao,
	login + @senha + @sal as senha_e_sal_variavel,
	convert(varchar(300), hashbytes('sha2_512', login + @senha + @sal), 2) as hash_das_senhas_sal_variavel
from @usuarios
go

Além disso, essa técnica de “sal variável” resolve um problema crítico: No salgamento tradicional, se 2 usuários tiverem a mesma senha, o mesmo hash será gerado.

 

No salgamento variável os hashes são sempre diferentes, pois os nomes de usuários serão sempre diferentes. Veja acima, João e Maria tem a mesma senha, ainda assim os hashes gerados são diferentes…

 

Apimentando senhas

O salgamento tradicional deixa uma senha mais complexa adicionando texto fixo a ela.

O salgamento variável adiciona “texto fixo” e “texto variável” a uma senha.

O apimentamento adiciona “texto aleatório” a uma senha!

Josué, isso não é o “salgamento variável” que você acabou de explicar?

Não. Salgamento variável adiciona texto previsível a nossa senha. Por exemplo: O ID ou o login de um usuário é uma informação imutável, relacionada e previsível!

 

Diferente do salgamento variável, o apimentamento adiciona texto completamente desconhecido a senha! Ou seja, a cada vez que você executa a mesma rotina para um usuário, o texto a ser adicionado a senha será diferente!

 

Veja abaixo exemplo:

 

print '--------------------------------------------------'
print 'Apimentamento tradicional'
print '--------------------------------------------------'
-- Adicionar "sal aleatório" para cada registro
declare @senha varchar(100)			= 'P4$$word'
declare @pimenta char(1)			= char((abs(checksum(newid())) % (256))) -- Sorteia um caractere da tabela ASC. A-Z (65 a 90)
declare @senha_pimenta varchar(300) = @senha + @pimenta
declare @hash varchar(300) = convert(varchar(300), hashbytes('sha2_512', @senha_pimenta), 2)
print 'Senha ....................: ' + @senha
print 'Pimenta...................: ' + @pimenta
print 'Senha + pimenta...........: ' + @senha_pimenta
print 'Senha + pimenta (sha2_512): ' + @hash
-- Como saber se o usuário digitou a senha certa? 
print '----------------------------------' 
declare @i smallint = 0
while @i <= 256 begin print 'Código ASC.....................: ' + convert(varchar, @i) print 'Pimenta do código ASC..........: ' + char(@i) print 'Hash guardado (original).......: ' + convert(varchar, @hash) print 'Hash com pimenta a ser testada.: ' + convert(varchar, convert(varchar(300), hashbytes('sha2_512', @senha + char(@i)), 2)) if convert(varchar(300), hashbytes('sha2_512', @senha + char(@i)), 2) = @hash begin print ' --> Senha válida! A pimenta é.: ' + char(@i) + ' (o login foi ' + convert(varchar, @i) + ' vezes mais lento).'
				break
			end
		print ''
		set @i+=1
	end
if @i > 256 print '--> Senha ERRADA!'
go

 

EXECUÇÃO #1:

 

EXECUÇÃO #2:

 

Observe que para um mesmo usuário e senha, cada execução do código gera uma pimenta diferente, o que gera um hash da senha também diferente.

 

Se a cada execução a pimenta é torna-se diferente, possivelmente a essa altura você esteja se perguntando: Como um sistema saberá se a senha de um usuário está correta?

 

A resposta é força bruta! Para saber se uma senha está correta, você terá de testar todas as pimentas possíveis… Abaixo o exemplo de um código que faz exatamente isso.

 

declare @i smallint = 0
while @i <= 256 begin print 'Código ASC.....................: ' + convert(varchar, @i) print 'Pimenta do código ASC..........: ' + char(@i) print 'Hash guardado (original).......: ' + convert(varchar, @hash) print 'Hash com pimenta a ser testada.: ' + convert(varchar, convert(varchar(300), hashbytes('sha2_512', @senha + char(@i)), 2)) if convert(varchar(300), hashbytes('sha2_512', @senha + char(@i)), 2) = @hash begin print ' --> Senha válida! A pimenta é.: ' + char(@i) + ' (o login foi ' + convert(varchar, @i) + ' vezes mais lento).'
				break
			end
		print ''
		set @i+=1
	end
if @i > 256 print '--> Senha ERRADA!'
go

 

Em nosso exemplo a pimenta pode ser qualquer um dos 256 caracteres da tabela ASC.

Logo, para testar se a senha informada é igual a senha armazenada testamos uma a uma as pimentas possíveis, até que encontremos a pimenta correta ou então que testemos todas e identifiquemos que a senha informada está incorreta.

 

Apimentando senhas – técnica dba-pro

A técnica de apimetamento adiciona grande segurança ao processo de proteção de informações, porém com a segurança temos também um aumento enorme de processamento e tempo de resposta, como você deve ter percebido se testou algumas vezes o código acima.

 

Como temos 256 possíveis pimentas e precisamos testar uma a uma, um processo de login pode demorar até 256 vezes mais usando o processo de apimentamento.

 

Para resolver esse lado negativo dessa excelente técnica de segurança, tenho uma dica que chamo de “apimentamento dba-pro”. Consiste em limitar as possíveis pimentas para que tenhamos segurança similar com muito menos perda de performance.

 

Para o exemplo em questão, ao invés de usar todos os caracteres da tabela ASC, podemos usar apenas os caracteres de ASC160 até ASC190. Dessa forma, temos um processo tão seguro quanto o apimentamento tradicional, porém no máximo 30 vezes mais lento, ao invés de até 256 vezes mais lento:

 

print '--------------------------------------------------'
print 'Apimentamento dba-pro: ínfo única + pimenta selecionada + sal'
print '--------------------------------------------------'
-- tabela asc parcial (de 161 a 190):
declare @a smallint = 161
while @a <= 190
	begin
		print convert(varchar, @a) + '-' + char(@a)
		set @a+=1
	end

-- Geração de hash sal + sal variável + pimenta
declare @user varchar(100)			= 'josue'
declare @senha varchar(100)			= 'P4$$word'
declare @sal varchar(300)			= ' "!@#$%&*()_+=/;:?|/<>][{}_-´`abcdefghijklmnopqrstuwxz1234567890áâàäéêèëíìïóôòöúûùüÁÂÀÉÊÈÍÎÌÏÓÔÒÚÛÙÜ'
declare @pimenta char(1)			= char((abs(checksum(newid())) % (190 - 161))+161) -- Tabela ASC de 161 a 190.
declare @senha_pimenta varchar(300) = @user + @senha + @pimenta + @sal
declare @hash varchar(300) = convert(varchar(300), hashbytes('sha2_512', @senha_pimenta), 2)
print 'Senha ....................: ' + @senha
print 'Pimenta...................: ' + @pimenta
print 'Senha + pimenta...........: ' + @senha_pimenta
print 'Senha (sha2_512)..........: ' + convert(varchar(300), hashbytes('sha2_512', @senha), 2)
print 'Senha + pimenta (sha2_512): ' + @hash

-- Validação da senha
declare @i int = 161
while @i <= 190
	begin
		if convert(varchar(300), hashbytes('sha2_512',@user + @senha + char(@i) + @sal), 2) = @hash 
			begin
				print 'Senha válida! A pimenta é.: ' + char(@i) + ' (o login foi ' + convert(varchar, @i - 161) + ' vezes mais lento).'
				break
			end
		set @i+=1
	end

Senhas, sal e pimenta

Para facilitar seus testes, aqui vai o script completo da aula de hoje:

 

[sociallocker id=”5114″]


------------------------------------------------------------------
-- Protegendo informações com sal e pimenta... :S
------------------------------------------------------------------
-----------------------------------------------
-- É fácil quebrar uma senha?
-----------------------------------------------
-- https://hashkiller.co.uk/sha1-decrypter.aspx
-- Hash SHA1: EAB2E06EAFEB391903483173F490BFA38E965488
print convert(varchar(300), hashbytes('sha', 'P4$$word'), 2)


print '--------------------------------------------------'
print 'Salgamento tradicional'
print '--------------------------------------------------'
-- Adicionar informações ao dado a ser protegido, dificultando cracking
declare @senha varchar(100)			= 'P4$$word'
declare @sal varchar(300)			= ' "!@#$%&*()_+=/;:?|/<>][{}_-´`abcdefghijklmnopqrstuwxz1234567890áâàäéêèëíìïóôòöúûùüÁÂÀÉÊÈÍÎÌÏÓÔÒÚÛÙÜ'
declare @senha_e_sal varchar(300)	= @senha + @sal
print 'Senha ................: ' + @senha
print 'Sal . ................: ' + @sal
print 'Senha + sal...........: ' + @senha_e_sal
print 'Senha (sha)...........: ' + convert(varchar(300), hashbytes('sha', @senha), 2)
print 'Senha e sal (sha).....: ' + convert(varchar(300), hashbytes('sha', @senha_e_sal), 2)
print 'Senha e sal (sha2_512): ' + convert(varchar(300), hashbytes('sha2_512', @senha_e_sal), 2)
print ''
go


print '--------------------------------------------------'
print 'Salgamento dba-pro: Sal variável + fixo'
print '--------------------------------------------------'
-- Adicionar "sal variável" para cada registro
declare @usuarios table (login varchar(300), senha varchar(300))
insert into @usuarios values ('joao', null)
insert into @usuarios values ('maria', null)
declare @senha varchar(100)	= 'P4$$word'
declare @sal varchar(300)   = ' "!@#$%&*()_+=/;:?|/<>][{}_-´`abcdefghijklmnopqrstuwxz1234567890áâàäéêèëíìïóôòöúûùüÁÂÀÉÊÈÍÎÌÏÓÔÒÚÛÙÜ'
select 
	login, 
	@senha as senha_dos_usuarios,
	@sal as sal_padrao,
	@senha + @sal as senha_e_sal,
	convert(varchar(300), hashbytes('sha2_512', @senha + @sal), 2) as hash_senha_e_sal_padrao,
	login + @senha + @sal as senha_e_sal_variavel,
	convert(varchar(300), hashbytes('sha2_512', login + @senha + @sal), 2) as hash_das_senhas_sal_variavel
from @usuarios
go


print '--------------------------------------------------'
print 'Apimentamento tradicional'
print '--------------------------------------------------'
-- Adicionar "sal aleatório" para cada registro
declare @senha varchar(100)			= 'P4$$word'
declare @pimenta char(1)			= char((abs(checksum(newid())) % (256))) -- Sorteia um caractere da tabela ASC. A-Z (65 a 90)
declare @senha_pimenta varchar(300) = @senha + @pimenta
declare @hash varchar(300) = convert(varchar(300), hashbytes('sha2_512', @senha_pimenta), 2)
print 'Senha ....................: ' + @senha
print 'Pimenta...................: ' + @pimenta
print 'Senha + pimenta...........: ' + @senha_pimenta
print 'Senha + pimenta (sha2_512): ' + @hash
-- Como saber se o usuário digitou a senha certa? 
print '----------------------------------' 
declare @i smallint = 0
while @i <= 256 begin print 'Código ASC.....................: ' + convert(varchar, @i) print 'Pimenta do código ASC..........: ' + char(@i) print 'Hash guardado (original).......: ' + convert(varchar, @hash) print 'Hash com pimenta a ser testada.: ' + convert(varchar, convert(varchar(300), hashbytes('sha2_512', @senha + char(@i)), 2)) if convert(varchar(300), hashbytes('sha2_512', @senha + char(@i)), 2) = @hash begin print ' --> Senha válida! A pimenta é.: ' + char(@i) + ' (o login foi ' + convert(varchar, @i) + ' vezes mais lento).'
				break
			end
		print ''
		set @i+=1
	end
if @i > 256 print '--> Senha ERRADA!'
go


print '--------------------------------------------------'
print 'Apimentamento dba-pro: ínfo única + pimenta selecionada + sal'
print '--------------------------------------------------'
-- tabela asc parcial (de 161 a 190):
declare @a smallint = 161
while @a <= 190
	begin
		print convert(varchar, @a) + '-' + char(@a)
		set @a+=1
	end

-- Geração de hash sal + sal variável + pimenta
declare @user varchar(100)			= 'josue'
declare @senha varchar(100)			= 'P4$$word'
declare @sal varchar(300)			= ' "!@#$%&*()_+=/;:?|/<>][{}_-´`abcdefghijklmnopqrstuwxz1234567890áâàäéêèëíìïóôòöúûùüÁÂÀÉÊÈÍÎÌÏÓÔÒÚÛÙÜ'
declare @pimenta char(1)			= char((abs(checksum(newid())) % (190 - 161))+161) -- Tabela ASC de 161 a 190.
declare @senha_pimenta varchar(300) = @user + @senha + @pimenta + @sal
declare @hash varchar(300) = convert(varchar(300), hashbytes('sha2_512', @senha_pimenta), 2)
print 'Senha ....................: ' + @senha
print 'Pimenta...................: ' + @pimenta
print 'Senha + pimenta...........: ' + @senha_pimenta
print 'Senha (sha2_512)..........: ' + convert(varchar(300), hashbytes('sha2_512', @senha), 2)
print 'Senha + pimenta (sha2_512): ' + @hash

-- Validação da senha
declare @i int = 161
while @i <= 190
	begin
		if convert(varchar(300), hashbytes('sha2_512',@user + @senha + char(@i) + @sal), 2) = @hash 
			begin
				print 'Senha válida! A pimenta é.: ' + char(@i) + ' (o login foi ' + convert(varchar, @i - 161) + ' vezes mais lento).'
				break
			end
		set @i+=1
	end


[/sociallocker]

CONCLUSÃO

Como você deve ter notado, as vezes pode ser um pouquinho chato de salgar e/ou apimentar uma senha ou informação sigilosa, mas não é complexo! Além disso, os termos podem parecer um pouco esquisitos a primeira vista, mas vale a pena dominar as técnicas pois adicionam uma excelente camada extra de segurança a sua aplicação.

Espero que também tenha gostado desse conteúdo.

 

Abraço do seu amigo Josué 🙂

2 respostas

  1. Boa tarde Josué,

    Achei bem legal a ideia de salgar e apimentar =).

    Eu havia realizado da seguinte forma:
    “Encriptografei” 2 vezes.
    Eu peguei o resultado da primeira CRIPTOGRAFIA e CRIPTOGRAFEI novamente.

    Sendo assim, acredito que funcione também!

    Obrigado!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *