Tabelas pré-computadas e tabelas rainbow funcionam porque o hash sem sal de uma dada entrada é sempre o mesmo valor. O salt remove exatamente essa premissa.

O que dá errado sem salt

Se as senhas são hasheadas de forma crua, hash("senha") é o mesmo em todo lugar. Uma única tabela pré-computada quebra essa conta em todos os sites de uma vez, e dois usuários que escolheram a mesma senha têm o mesmo hash armazenado, visível num vazamento de banco de dados.

O que é um salt

Um salt é um valor aleatório por senha, tipicamente de 16 bytes ou mais, gerado quando a senha é definida e armazenado às claras junto ao hash. O registro armazenado é, na prática, hash(salt + senha) junto com o próprio salt.

Por que as tabelas param de funcionar

Para usar uma tabela pré-computada contra um hash com sal, o atacante teria que tê-la construído usando este salt específico. Com um salt único por linha, nenhuma tabela pode ser reaproveitada entre contas, e a pré-computação não rende nada: o atacante é forçado a voltar a calcular hashes para um alvo de cada vez.

O que o salt não faz

O salt não desacelera um ataque contra um único salt conhecido. Uma vez que o atacante tem o salt (ele não é secreto), ainda pode tentar e verificar contra aquele alvo tão rápido quanto o hash permitir. Derrotar isso é tarefa de uma KDF lenta, não do salt.

Um salt não é secreto e não substitui um hash de senha lento. O armazenamento correto de senhas precisa dos dois: um salt único para matar a pré-computação e uma função deliberadamente lenta para tornar cada tentativa cara.