O salt é utilizado no processo de hashing para forçar sua unicidade. O salt aumenta a complexidade do hash. Sem onerar ou dificultar a senha do usuário. E com isso se proteger de ataques como Rainbow tables.

O Hash

O Hash é uma função deterministica. Isso quer dizer que, dada uma certa entrada, ela produzirá sempre a mesma saída.

Adicionar um salt aleatório, garante que o hash produzido será sempre diferente. Isso protege seu repositório de um Rainbow table attack. E diminui a eficácia de um brute force ou dictionary attack.

Entendendo o problema

Supondo que um usuário tenha uma senha 12345678. O hash gerado será 25D55AD283AA400AF464C76D713C07AD (MD5).


usuario senha
joao 7C222FB2927D828AF22F592134E8932480637C0D
maria A7D579BA76398070EAE654C30FF153A4C273272A
jose 4A3487E57D90E2084654B6D23937E75AF5C8EE55
bruno 7C222FB2927D828AF22F592134E8932480637C0D
diana A7D579BA76398070EAE654C30FF153A4C273272A

Repare na tabela os usuários bruno e joão. Apesar de não saber o password é possivel identificar que eles possuem o mesmo hash. Como o hash é deterministico. É válido afirmar que ambos possuem a mesma senha.

Antes de continuar veja o que já passou

Se você chegou aqui neste artigo e não leu os anteriores, é leitura obrigatória para entender como chegamos aqui:

Como hashes são crackeados

Os métodos mais conhecidos atualmente para crackear um hash são:

  • Dictionary attack
  • Brute Force attack
  • Lookup Table
  • Reverse Lookup Table
  • Rainbow Tables

O salt protege seu repositório de três deles. Lookup table, reverse lookup e rainbow table.

Dictionary e Brute force attack

Dictionary Attack

Trying 1234578      : failed
Trying 10203040     : failed
Trying meucachorro  : failed
...
Trying minhamae     : failed
Trying minhasenhasecreta: success!
Brute Force Attack

Trying aaaa : failed
Trying aaab : failed
Trying aaac : failed
...
Trying zzab : failed
Trying zzac : success!

A maneira mais fácil de crakear um password é por tentative error. E nesse caso, os ataques mais comuns são dictionary e brute force.

O brute force é o método mais lento. No entanto, uma maquina mediana. Com duas placas de video ATI Radeon 7970 (R$ 800.00 no Mercado Livre) e utilizando o hashcat. Consegue calcular um password de 6 caracteres. Incluindo todas as letras minusculas, maiusculas, numeros e caracteres especiais do teclado: Em miseros 47 segundos. Mais detalhes sobre isso em Segurança - Parte 2 - Hash em senhas.

O brute force tenta todas as possibilidades de combinações de caracteres, incluindo letras, números e caracteres especiais.

Já o dictionary attack é um ataque mais efetivo, quando comparado ao brute-force. Pois utiliza palavras. Alguns dicionarios, possuem uma coleção de senhas de outros bancos de dados vazados, aumentando ainda mais sua efetividade.

Lookup table

Essa é uma técnica bem efetiva. Ao invés calcular o Hash apartir da senha. Ele utiliza uma tabela com milhares de hashes já calculados.

Searching: 7C222FB2927D828AF22F592134E8932480637C0D: FOUND: 12345678
Searching: 040069E821AF22F61491D2040C481C97:  not in database
Searching: A7D579BA76398070EAE654C30FF153A4C273272A: FOUND: 10203040
Searching: 6E22255F7B6C604A2992FF97E1F5B2CA:  not in database
Searching: 65CC61F8A26C3480CA3C6714D67BBC3F: FOUND: minhamae
Searching: BCD3A64ED1C945565F54FFFBA26071E9: FOUND: minhasupersenha
Searching: F5BB0C8DE146C67B44BABBF4E6584CC0:  not in database
Searching: D017FBF96868A24E9E144E7BF4B2260D:  not in database


Reverse Lookup table

Esta técnica permite ao atacante aplicar um dictionary ou brute force a diversos hashes simultaneamente. Ao invés de atacar um usuário até tentar quebrar sua senha. Gera um hash e tenta localizar todos os usuários que possuem aquela senha.

Searching for hash(12345678) in users' ...     : Matches [joao, bruno, ricardo]
Searching for hash(10203040) in users' ... : Matches [jose, aaamaria, diana]
Searching for hash(minhasenhasecreta) in users' ...   : Matches [wilson, lula, moro]
Searching for hash(@Password1) in users' ...    : Matches [mario, manoel, dilma]
Searching for hash(@pass1) in users'...  : No users used this password

Rainbow table


rainbow table

Um Rainbow table requer duas coisas: uma função de hashing e outra de reduction.
E através de um processo de hash e reduction, cria uma chain para mapear e diminuir o consumo de memória, sem ter que ficar calculando o hash de cada senha. É um processo complexo. Mas funciona muito similar ao Lookup table.

São considerados time-memory trade-off. Isso é basicamente quando você aceita um tempo de execução mais longo em favor de menos requisitos de memória. Com essa tecnica o tamanho das tabelas pode ser extremamente reduzido. Mas ainda assim elas são gigantescas. Veja algumas tabelas para download aqui.

Para entender mais sobre como funciona rainbow-tables, acesse essa documentação.

Salt

Lookup tables e Rainbow tables só funcionam porque cada senha é hasheada exatamente da mesma maneira.

Se dois usuários tiverem a mesma senha, eles terão os mesmos hashes. É possivel evitar isso adicionando um salt ao hash.

O salt é uma string aleatória. Que pode ser concatenado (préfixando ou pós-fixando) na senha.

MD5: 12345678 =              25D55AD283AA400AF464C76D713C07AD
MD5: 12345678 + B5dk6s93wu = DED4A56E0FC17B4FA7C6A0B160EF6383
MD5: 12345678 + vEO6GHigtl = E13BE10696873EAEC198328FB071D445
MD5: 12345678 + L7PKlspdH1 = C18B0EE74EDE5567EE5CA3CF9227DE4A
MD5: 12345678 + cKpCYq4P5J = E9458986AAB6554D449C4C310EFF0C2B

Isso torna o hash de uma senha em uma string completamente diferente. Para verificar se uma senha está correta, é necessário o salt. Ela é normalmente armazenada no repositório no mesmo local do hash, ou junto dele.

O salt não precisa ser secreto. Só o fato de randomizar a Hash já é o suficiente para tornar as Lookup table e rainbow table ineficazes.

Um atacante não saberá com antecedência qual será o salt, portanto, não conseguirá pré-calcular uma Lookup table ou uma rainbow table.

O salt precisa ser aleatório, assim o ataque Reverse Lookup table também será ineficiente.

Não crie seu próprio salt

Aqui vale a mesma regra para hash de senhas. Nunca crie salt. Existem bibliotecas já desenvolvida com esse próposito. Funções de hash são incrivelmente complexas, assim como as de salt.

Só crie seu salt em último caso.

Salts ineficientes

Utilizar um único salt, tem o mesmo efeito que não utilizar nenhum. Na prática dois usuários com a mesma senha terá o mesmo hash. Perdendo totalmente seu objetivo.

Um salt deve ser grande, pois senão o atacante poderá montar Lookup tables ou Rainbow attack em cima do Salt.

Uma regra comumente utilizada é usar um salt com o mesmo tamanho da saída da função hash. Por exemplo, se utilizar o algoritimo SHA256, de 256 bits o salt deve ter 256bits aleatórios.

Playground

Quer saber o quão poderoso é um Lookup table? Vá até este site e coloque esses hashes:

670F8574BD93DD78BD568DAB84C6733A
25D55AD283AA400AF464C76D713C07AD
7C222FB2927D828AF22F592134E8932480637C0D
61FF76C0A46C9F653F4B1EE3D251AAC860263E15
2A6D337010BFD13831EB441CD9FB763D

Conclusão

Salt, assim como o hash de senha é uma segunda linha de defesa. O atacante já está com acesso ao repositório. Seja por um SQL Injection, ou porque extraviou a fita de backup. Pode ser um dev ou DBA da própria empresa.

Seus usuários estão inserindo a senha deles seu aplicativo. Estão confiando em você a segurança deles.

Se a primeira linha de defesa for quebrada e as senhas de seus usuários estiverem desprotegidas, os hackers poderão usar essas senhas para comprometer as contas outros sites e serviços. A maioria das pessoas utiliza a mesma senha em vários lugares.

Não é apenas a sua segurança que está em risco, é dos seus usuários. Você é responsável pela segurança dos seus usuários.

Abordamos mais um tópico sobre gerenciamento de senhas. E aqui novamente vale lembrar Uma autenticação feita por amadores, é uma autenticação amadora.
(Parafraseando a frase Amateurs Produce Amateur Cryptography)

Deixe seus comentários e feedbacks!

Referências