Sal não aleatório para hashes de senha

89

ATUALIZAÇÃO: Recentemente, aprendi com esta pergunta que em toda a discussão abaixo, eu (e tenho certeza que outros também fizeram) fiquei um pouco confuso: O que eu continuo chamando de tabela de arco-íris, na verdade é chamado de tabela de hash. As tabelas de arco-íris são criaturas mais complexas e, na verdade, são uma variante de Hellman Hash Chains. Embora eu acredite que a resposta ainda seja a mesma (uma vez que não se resume à criptoanálise), parte da discussão pode ser um pouco distorcida.
A pergunta: " O que são tabelas arco-íris e como são usadas? "


Normalmente, eu sempre recomendo usar um valor aleatório criptograficamente forte como sal, para ser usado com funções hash (por exemplo, para senhas), como para proteção contra ataques de Rainbow Table.

Mas é realmente criptograficamente necessário que o sal seja aleatório? Qualquer valor exclusivo (exclusivo por usuário, por exemplo, userId) seria suficiente a esse respeito? Na verdade, impediria o uso de uma única tabela do arco-íris para quebrar todas (ou a maioria) das senhas no sistema ...
Mas a falta de entropia realmente enfraquece a força criptográfica das funções hash?


Observe, não estou perguntando sobre por que usar o salt, como protegê-lo (não precisa ser), usando um único hash constante (não) ou que tipo de função hash usar.
Apenas se o sal precisa de entropia ou não.


Obrigado a todos pelas respostas até agora, mas gostaria de me concentrar nas áreas com as quais estou (um pouco) menos familiarizado. Principalmente implicações para a criptoanálise - eu apreciaria muito se alguém tivesse alguma entrada do PoV criptomatemático.
Além disso, se houver vetores adicionais que não foram considerados, essa é uma ótima entrada também (consulte @Dave Sherohman point em vários sistemas).
Além disso, se você tiver alguma teoria, ideia ou prática recomendada - faça o backup com provas, cenário de ataque ou evidências empíricas. Ou mesmo considerações válidas para compensações aceitáveis ​​... Estou familiarizado com as Melhores Práticas (B maiúsculo P) sobre o assunto, gostaria de provar que valor isso realmente fornece.


EDIT: Algumas respostas muito boas aqui, mas acho que como @Dave diz, tudo se resume a Rainbow Tables para nomes de usuário comuns ... e possíveis nomes menos comuns também. No entanto, e se meus nomes de usuário forem globalmente exclusivos? Não necessariamente exclusivo para meu sistema, mas para cada usuário - por exemplo, endereço de e-mail.
Não haveria incentivo para construir um RT para um único usuário (como @Dave enfatizou, o salt não é mantido em segredo), e isso ainda impediria o agrupamento. O único problema seria que eu poderia ter o mesmo e-mail e senha em um site diferente - mas o sal não iria impedir isso de qualquer maneira.
Então, tudo se resume à criptoanálise - a entropia é necessária ou não? (Meu pensamento atual é que não é necessário do ponto de vista da criptoanálise, mas é por outras razões práticas.)

Ávido
fonte
Devo dizer que estou confuso com muitas das respostas abaixo. O ponto principal do uso do salt é simplesmente impedir o ataque da rainbow table, portanto, qualquer coisa exclusiva do usuário deve fazer, pois força o invasor a recriar uma rainbow table para cada salt. meu 2c.
Goran
Se o sal é necessário para, por exemplo. site, você costuma ter ids em urls. Se o invasor souber (e presumimos que sabe) que a senha salt é userid + username, é bastante fácil modificar o ataque para evitar o valor salt.
dmajkic
@dmajkic, salt tem como objetivo prevenir ataques RT e diferenciar as mesmas senhas para usuários diferentes. Isso é um dado adquirido, mesmo com nomes de usuário.
AviD
@AviD: Isso é verdade. Mas se eu sei meu hash para meu passe, e sei que salt é meu nome de usuário, posso criar facilmente um valor de passe hash para qualquer palavra do dicionário e compará-lo com o hash de passagem de outra pessoa. É por isso que o tempo é melhor do que o nome de usuário.
dmajkic
1
Acabei de encontrar um artigo no site do PHP Security Consortium que em seu exemplo usa um número aleatório com hash md5 como o salt phpsec.org/articles/2005/password-hashing.html
helloworlder

Respostas:

156

O sal é tradicionalmente armazenado como um prefixo da senha com hash. Isso já o torna conhecido por qualquer invasor com acesso ao hash de senha. Usar o nome de usuário como sal ou não não afeta esse conhecimento e, portanto, não teria efeito na segurança de um único sistema.

No entanto, usar o nome de usuário ou qualquer outro valor controlado pelo usuário como salt reduziria a segurança entre os sistemas, já que um usuário que tivesse o mesmo nome de usuário e senha em vários sistemas que usam o mesmo algoritmo de hash de senha acabaria com o mesmo hash de senha cada um desses sistemas. Não considero isso uma responsabilidade significativa porque eu, como um invasor, tentaria primeiro as senhas que uma conta de destino usou em outros sistemas antes de tentar qualquer outro meio de comprometer a conta. Hashes idênticos apenas me diriam com antecedência que a senha conhecida funcionaria, eles não tornariam o ataque real mais fácil. (Observe, porém, que uma comparação rápida dos bancos de dados de contas forneceria uma lista de alvos de prioridade mais alta, já que me diria quem está e quem não está reutilizando senhas.)

O maior perigo dessa ideia é que os nomes de usuário são comumente reutilizados - praticamente qualquer site que você queira visitar terá uma conta de usuário chamada "Dave", por exemplo, e "admin" ou "root" são ainda mais comuns - o que tornaria construção de rainbow tables direcionando usuários com esses nomes comuns muito mais fácil e eficaz.

Ambas as falhas podem ser resolvidas de forma eficaz adicionando um segundo valor de sal (fixo e oculto ou exposto como sal padrão) à senha antes de fazer o hash, mas, nesse ponto, você pode muito bem estar usando o sal entrópico padrão de qualquer maneira de trabalhar o nome de usuário nele.

Editado para adicionar: Muitas pessoas estão falando sobre entropia e se a entropia no sal é importante. É, mas não pelo motivo que a maioria dos comentários parecem pensar.

O pensamento geral parece ser que a entropia é importante para que o sal seja difícil para um invasor adivinhar. Isso é incorreto e, na verdade, completamente irrelevante. Como foi apontado algumas vezes por várias pessoas, os ataques que serão afetados pelo salt só podem ser feitos por alguém com o banco de dados de senhas e alguém com o banco de dados de senhas pode apenas verificar o que é o salt de cada conta. Se é possível adivinhar ou não, não importa quando você pode pesquisá-lo trivialmente.

A razão pela qual a entropia é importante é evitar o agrupamento de valores de sal. Se o salt é baseado no nome de usuário e você sabe que a maioria dos sistemas terá uma conta chamada "root" ou "admin", então você pode fazer uma tabela arco-íris para esses dois sais e isso quebrará a maioria dos sistemas. Se, por outro lado, um sal aleatório de 16 bits for usado e os valores aleatórios tiverem distribuição aproximadamente uniforme, você precisará de uma tabela arco-íris para todos os 2 ^ 16 sais possíveis.

Não se trata de impedir que o invasor saiba o que é o sal de uma conta individual, mas de não dar a ele o alvo grande e gordo de um único sal que será usado em uma proporção substancial de alvos em potencial.

Dave Sherohman
fonte
Acordado. Eu colocaria mais ênfase na reutilização de nomes de usuário, pois acho que é o ataque com maior probabilidade de ser bem-sucedido contra sistemas hipotéticos que usam o nome de usuário como um sal, que teria falhado contra um sistema usando sal aleatório.
Steve Jessop
Agradeço seu ponto sobre segurança entre sistemas. Além disso, acho que no futuro não é improvável que haja tabelas de arco-íris específicas do usuário ...
AviD
@AviD: Você acha? Esse é um vetor de ataque bastante específico.
David Grant
2
Não para gerar sais, não. Os únicos ataques afetados pelo salt são aqueles feitos diretamente contra as senhas com hash. Um ataque não pode fazer esse tipo de ataque, a menos que tenha uma cópia de seu banco de dados de senha, que também conterá os sais. Uma vez que o invasor já terá os sais em sua posse, eles exigem apenas entropia suficiente para evitar que várias senhas tenham o mesmo sal, o que qualquer (P) RNG básico fornecerá.
Dave Sherohman
3
@ acidzombie24: Usar um único sal fixo (geralmente chamado de "nonce" na minha experiência) para todas as senhas é menos seguro do que usar um sal aleatório exclusivo para cada senha, pois ainda permite que um invasor determine trivialmente se duas ou mais contas compartilham a mesma senha. Por outro lado, o nonce provavelmente seria armazenado em seu código em vez de no banco de dados, de modo que um invasor que possui apenas seu banco de dados não terá acesso a ele; por causa disso, a opção mais segura é usar um nonce para todo o sistema (armazenado no código) e um salt por senha (armazenado no banco de dados).
Dave Sherohman
29

Usar um sal de alta entropia é absolutamente necessário para armazenar senhas com segurança.

Pegue meu nome de usuário 'gs' e adicione-o à minha senha 'MyPassword' fornece gsMyPassword. Isso é facilmente quebrado usando uma rainbow-table porque se o nome de usuário não tiver entropia suficiente, pode ser que esse valor já esteja armazenado na rainbow-table, especialmente se o nome de usuário for curto.

Outro problema são os ataques em que você sabe que um usuário participa de dois ou mais serviços. Existem muitos nomes de usuário comuns, provavelmente os mais importantes são admin e root. Se alguém criou uma tabela de arco-íris com sais com os nomes de usuário mais comuns, ele poderia usá-los para comprometer contas.

Eles costumavam ter um sal de 12 bits . 12 bits são 4096 combinações diferentes. Isso não era seguro o suficiente porque tanta informação pode ser facilmente armazenada hoje em dia . O mesmo se aplica aos 4096 nomes de usuário mais usados. É provável que alguns de seus usuários escolham um nome de usuário que pertence aos nomes de usuário mais comuns.

Encontrei este verificador de senha que analisa a entropia de sua senha. Ter uma entropia menor nas senhas (como usar nomes de usuário) torna muito mais fácil para as tabelas do arco-íris, pois elas tentam cobrir pelo menos todas as senhas com baixa entropia, porque são mais prováveis ​​de ocorrer.

Georg Schölly
fonte
1 para um bom ponto, no entanto, você está falando sobre uma mesa de arco-íris potencialmente enorme . Para cobrir todos os valores de comprimento de gsMyPassword (assumindo combinação alfanumérica de maiúsculas e minúsculas), são necessárias 36 ^ 12 linhas na tabela!
David Grant
Como acompanhamento: o projeto de tabela de arco-íris distribuído tem 63.970 hashes rachados, mas 36 ^ 12 é 4.738.381.338.321.616.896!
David Grant
Obrigado, e isso faz sentido - mas como Mr.PotatoHead apontou, você ainda está expandindo seu espaço além da possibilidade razoável de crackear com RT. Além disso, supondo que meus nomes de usuário tenham pelo menos 6 a 8 caracteres - que valor adicional necessário a entropia fornece?
AviD
@Potato: você assume uma tabela arco-íris contendo todas as combinações possíveis de caracteres alfanuméricos. Este não precisa ser o caso, uma tabela de arco-íris eficaz conterá hashes para senhas / hashes comuns. O sal existe para proteger contra ataques de dicionário ou combinação arco-íris / dicionário.
Guillaume
3
Usar o nome de usuário como o sal também é uma má ideia para sistemas onde há uma conta de alto privilégio chamada previsivelmente: "Administrador" no Windows, "root" no * nix, "sa" no MSSQL etc.
ninguém
8

É verdade que o nome de usuário sozinho pode ser problemático, pois as pessoas podem compartilhar nomes de usuários entre diferentes sites. Mas não deveria ser problemático se os usuários tivessem um nome diferente em cada site. Então, por que não torná-lo único em cada site. Hash a senha mais ou menos assim

função de hash ("www.yourpage.com /" + nome de usuário + "/" + senha)

Isso deve resolver o problema. Não sou um mestre em criptanálise, mas tenho certeza de que o fato de não usarmos alta entropia tornaria o hash mais fraco.

Konne
fonte
Eu acredito que você está certo de que isso é suficiente. No entanto, dado que os hashes são um campo matemático complicado e é muito possível que sais de baixa entropia tornem os hashes mais fáceis de adivinhar no futuro (especialmente quando os hashes são quebrados), eu não apostaria na segurança, quando o comprovado solução mais segura não é muito mais cara.
Georg Schölly de
7

Gosto de usar os dois: um salt aleatório por registro de alta entropia, mais o ID exclusivo do próprio registro.

Embora isso não acrescente muito à segurança contra ataques de dicionário, etc., remove o caso marginal em que alguém copia seu salt e hash para outro registro com a intenção de substituir a senha por sua própria.

(Reconheço que é difícil pensar em uma circunstância em que isso se aplique, mas não vejo nenhum mal em cintos e suspensórios quando se trata de segurança.)

teedyay
fonte
Gosto da ideia de vincular a senha ao usuário. Mas se o invasor pode alterar a senha, ele certamente também pode alterar o id.
Georg Schölly
Depende de qual é o ID: eu uso a chave primária da tabela, que você realmente não pode alterar à vontade. TBH, se o hacker está escrevendo em seu banco de dados, você já está em apuros ...
teedyay
3
Nah, eu gosto disso. Um invasor geralmente é um "insider". Eu poderia imaginar cenários em que o que ele está procurando não esteja no banco de dados, mas se ele puder sobrescrever as credenciais no banco de dados, ele poderá se autenticar para fazer o que quiser.
erickson
1
Bom ponto. Achamos que fica cada vez mais difícil adicionar o primeiro usuário a um novo banco de dados: efetivamente tornamos nossos aplicativos tão seguros que mal podemos hackea-los. [Além disso, use um sal específico do aplicativo para que você não possa copiar credenciais de um banco de dados para outro.]
terça
Finalmente encontrei alguém dizendo isso: adicionar algo específico do usuário ao sal. Isso evita que um invasor copie algumas credenciais para outro usuário e também evita que um hacker adivinhe qualquer senha se ele conseguir acessar o campo hash e salt na tabela. Mais uma coisa que gosto de fazer: não usar um número redondo de iterações no hashing. Não vá para 10k ou 20k, mas algo como 19835.
Andrew
3

Se o sal for conhecido ou facilmente adivinhado, você não aumentou a dificuldade de um ataque de dicionário. Pode até ser possível criar uma tabela de arco-íris modificada que leve em consideração um sal "constante".

O uso de sais exclusivos aumenta a dificuldade de ataques de dicionário BULK.

Ter um valor de sal único e criptograficamente forte seria o ideal.

HUAGHAGUAH
fonte
2
O ponto principal da tabela arco-íris é que os valores são pré-gerados, e se você está gerando a tabela para um valor (por exemplo, senha) MAIS uma determinada constante, essa é uma tabela totalmente diferente, e você também pode tente o resultado hash diretamente. :)
David Grant
1
Um hash constante não vale nada. Todas as senhas podem ser quebradas usando uma única tabela arco-íris. O propósito do sal é que é impossível criar uma mesa arco-íris.
Georg Schölly
1
@gs - Não vejo por que você não pode construir uma tabela de arco-íris que "inclua" os efeitos de um sal constante. O espaço de ataque (a senha) não terá mudado, então a tabela não precisará crescer, apenas ser recalculada.
HUAGHAGUAH
@Potato - depende da compensação. Se os 20k logins de sua empresa foram todos hash com o mesmo sal constante, pode ser mais barato calcular uma nova tabela de arco-íris do que atacá-los individualmente por dicionário. Daí minha ênfase em "BULK".
HUAGHAGUAH
3

Eu diria que, desde que o sal seja diferente para cada senha, você provavelmente estará bem. O ponto principal é que você não pode usar a tabela rainbow padrão para resolver todas as senhas no banco de dados. Portanto, se você aplicar um sal diferente a cada senha (mesmo que não seja aleatório), o invasor basicamente terá que calcular uma nova tabela de arco-íris para cada senha, já que cada senha usa um sal diferente.

Usar um sal com mais entropia não ajuda muito, porque o invasor, neste caso, presume-se que já tenha o banco de dados. Uma vez que você precisa ser capaz de recriar o hash, você já deve saber o que é o sal. Portanto, você precisa armazenar o sal ou os valores que constituem o sal em seu arquivo. Em sistemas como o Linux, o método para obter o sal é conhecido, portanto, não adianta ter um sal secreto. Você deve presumir que o invasor que possui seus valores de hash provavelmente conhece seus valores de sal também.

Kibee
fonte
3
“O ponto principal é que você não pode usar a tabela padrão do arco-íris para resolver todas as senhas do banco de dados”. Discordo. A questão é que você não pode usar uma tabela de arco-íris padrão para resolver qualquer senha. Se o sal for o nome de usuário, a tabela de arco-íris para "root" pode quebrar o pw do root.
Steve Jessop
Essa é provavelmente a única regra que realmente importa. Basicamente, você deseja que a senha seja algo único em seu sistema, mas não importa o que seja. No entanto, ainda pode ser algo simples. Você não precisa de muita entropia.
Kibbee
Este era o meu pensamento também - mas fiquei preso no "provavelmente tudo bem". Ainda não vejo essa teoria sendo provada - ou pelo menos verificado que não há implicações na criptoanálise.
AviD
@onebyone: Se o salt consiste em nome de usuário + valor local constante (geralmente uso ':'), isso ainda destrói RTs padronizados, a menos que haja uma variedade deles que inclua nomes de usuário comuns e valores salt estáticos comuns. Prefiro suspeitar que não seja o caso.
nsayer
Junto com nsayer. Você poderia usar uma string constante de todo o sistema, para a qual não haveria um RT pré-gerado, como # (D83d8, junto com o nome de usuário como o sal, e isso provavelmente impediria quaisquer ataques de rainbow table.
Kibbee
3

A força de uma função hash não é determinada por sua entrada!

Usar um salt conhecido do invasor obviamente torna a construção de uma tabela de arco-íris (especialmente para nomes de usuário embutidos em código como root ) mais atraente, mas não enfraquece o hash . Usar um sal desconhecido para o invasor tornará o sistema mais difícil de atacar.

A concatenação de um nome de usuário e senha ainda pode fornecer uma entrada para uma tabela de arco-íris inteligente, portanto, usar um sal de uma série de caracteres pseudo-aleatórios, armazenados com a senha em hash, é provavelmente uma ideia melhor. Como ilustração, se eu tivesse o nome de usuário "batata" e a senha "cerveja", a entrada concatenada para seu hash seria "potatobeer", que é uma entrada razoável para uma tabela de arco-íris.

Alterar o salt cada vez que o usuário altera sua senha pode ajudar a derrotar ataques prolongados, como faria a aplicação de uma política de senha razoável, por exemplo, maiúsculas e minúsculas, pontuação, comprimento mínimo, alteração após n semanas.

No entanto, eu diria que sua escolha de algoritmo de resumo é mais importante. O uso de SHA-512 será mais doloroso para quem está gerando uma tabela arco-íris do que o MD5, por exemplo.

David Grant
fonte
A força da função não muda, mas a saída definitivamente muda. Se a entrada pode ser influenciada ou conhecida, então talvez algo possa ser deduzido sobre o valor do hash. Esse é o risco.
Martin Carpenter
@Martin: A única coisa que você deve ser capaz de deduzir do valor do hash é se você tem uma correspondência ou não! Colocar "roota" ou "rootb" (onde "a" e "b" representam a senha) em uma função hash fornecerá uma saída radicalmente diferente.
David Grant
Os sais são conhecidos por um invasor usando tabelas arco-íris.
Georg Schölly
O servidor precisa conhecer o salt não criptografado (para verificar a senha em relação ao hash), portanto, pode-se presumir que um invasor tem acesso ao salt ou pode obtê-lo facilmente.
Georg Schölly
Certo, certo, isso é um dado - para ser mais específico, eu quis dizer a força do criptossistema geral (ou subsistema, hashes wrt).
AviD
1

O sal deve ter o máximo de entropia possível para garantir que, se um determinado valor de entrada for hash várias vezes, o valor hash resultante será, o mais próximo possível, sempre diferente.

Usar valores de sal em constante mudança com o máximo de entropia possível no sal garantirá que a probabilidade de hash (digamos, senha + salt) produzirá valores de hash totalmente diferentes.

Quanto menos entropia no sal, mais chance você tem de gerar o mesmo valor de sal, pois, portanto, maior a chance de gerar o mesmo valor de hash.

É a natureza do valor hash ser "constante" quando a entrada é conhecida e "constante" que permite que ataques de dicionário ou tabelas de arco-íris sejam tão eficazes. Variando o valor de hash resultante tanto quanto possível (usando valores de sal de alta entropia) garante que o hash da mesma entrada + random-salt produzirá muitos resultados de valor de hash diferentes, derrotando (ou pelo menos reduzindo muito a eficácia) a tabela arco-íris ataques.

CraigTP
fonte
Novamente, não estou me referindo ao uso de um único sal constante - em vez de um valor não aleatório, mas exclusivo do usuário. Por exemplo, userId.
AviD
A questão toda é que seu valor de sal nunca deve ser constante. Cada coisa que você hash, seja o mesmo valor de "entrada" ou não, deve ter um sal diferente. Dave Sherohman explica as desvantagens de usar até mesmo valores exclusivos do usuário que essencialmente permanecem os mesmos com cada cálculo de hash.
CraigTP de
-1

Entropia é o ponto de valor do Sal.

Se houver alguma "matemática" simples e reproduzível por trás do sal, então é o mesmo que o sal não está lá. Apenas adicionar valor ao tempo deve ser suficiente.

dmajkic
fonte
Eu não entendo esse comentário. Você diz "usa entropia" e depois: "usa tempo" ??
Martin Carpenter
se o nome de usuário for usado para sal, não é entrópico o suficiente. Mas se você usar nome de usuário + data e hora atual - é, uma vez que é difícil adivinhar quando exatamente o salt foi criado.
dmajkic
"entrópico o suficiente" é subjetivo; é o seu padrão. Basear esse valor no tempo pode não ser adequado.
Martin Carpenter
Não existe "aleatoriedade absoluta e verdadeira". Cabe a nós dizer quando é "bom o suficiente". Se você acha que, neste caso, o tempo não é suficiente, use outra coisa. stackoverflow.com/questions/84556/…
dmajkic
Na verdade, o ponto importante é fazer com que cada resultado hash seja único - para evitar (a) ataques de rainbow table e (b) identificação de senha idêntica. A questão é: para que mais é necessária a entropia, se é que é necessária?
AviD