Onde você armazena suas cordas de sal?

Eu sempre usei uma string de sal por input adequada ao hashing de senhas para armazenamento de database. Para minhas necessidades, armazenar o sal no database ao lado da senha com hash sempre funcionou bem.

No entanto, algumas pessoas recomendam que o sal seja armazenado separadamente do database. O argumento deles é que, se o database for comprometido, um atacante ainda pode construir uma tabela de arco-íris levando em conta uma cadeia de salt em particular, a fim de quebrar uma conta de cada vez. Se essa conta tiver privilégios de administrador, talvez ele nem precise violar outras.

Do ponto de vista da segurança, vale a pena armazenar sais em um lugar diferente? Considere um aplicativo da Web com o código do servidor e o database na mesma máquina. Se os sais forem armazenados em um arquivo simples nessa máquina, é provável que, se o database for comprometido, o arquivo de sais também esteja.

Existe alguma solução recomendada para isso?

O ponto das tabelas de arco-íris é que elas são criadas antecipadamente e distribuídas em massa para economizar tempo de cálculo para outras pessoas – é preciso muito tempo para gerar tabelas de arco-íris instantaneamente, como quebrar a combinação senha + sal diretamente efetivamente o que está sendo feito ao gerar tabelas de arco-íris está pré-executando os cálculos para forçar o hash brutalmente), portanto, o argumento de que saber o sal que alguém poderia “gerar uma mesa de arco-íris” é espúrio.

Não há nenhum ponto real em armazenar sais em um arquivo separado, desde que eles estejam em uma base por usuário – o ponto do sal é simplesmente fazer com que uma tabela de arco-íris não consiga quebrar todas as senhas no database.

Vou fornecer uma visão um pouco diferente disso.

Eu sempre guardo o sal misturado com o hash de senha salgada.

Por exemplo, colocarei a primeira metade do sal antes do hash salgado da senha e a última metade do sal depois do hash salgado da senha. O aplicativo está ciente desse design, portanto, pode buscar esses dados e obter o hash de sal e senha salgados.

Minha justificativa para essa abordagem:

Se os dados de senha / hash forem comprometidos e caírem nas mãos de um invasor, o invasor não saberá qual é o aspecto salgado dos dados. Dessa forma, um invasor não pode executar praticamente um ataque de força bruta para obter uma senha que corresponda ao hash, pois ele não sabe o hash para começar e não tem como saber quais partes dos dados são partes do sal, ou partes do hash de senha salgada (a menos que ele conheça a lógica de autenticação de seu aplicativo ).

Se o hash de senha salgada for armazenado como está, um ataque de força bruta poderá ser executado para obter uma senha que, quando salgada e com hash, produz os mesmos dados que o hash de senha salgada.

No entanto, por exemplo, mesmo se o hash de senha salgada fosse armazenado como está, mas pré-pendente com um único byte random, contanto que o invasor não saiba que esse primeiro byte deve ser descartado, isso também aumentaria a dificuldade de ataque. Seu aplicativo saberia descartar o primeiro byte dos dados quando usado para autenticar seu usuário.

A conclusão para isso ..

1) Nunca armazene os dados que seu aplicativo de autenticação usa em sua forma exata.

2) Se possível, mantenha sua lógica de autenticação em segredo para maior segurança.

Vá um passo adiante.

Se você não puder manter a lógica de autenticação do seu aplicativo secreta – muitas pessoas sabem como seus dados são armazenados no database. E suponha que você tenha decidido armazenar o hash de senha salgada misturado com o sal, com um pouco do sal prefixando o hash de senha salgada e o restante do sal anexando-o.

Ao gerar o sal random, você também pode decidir aleatoriamente que proporção do seu sal armazenará antes / depois do hash de senha salgada.

Por exemplo, você gera um sal random de 512 bytes. Você acrescenta o sal à sua senha e obtém o hash SHA-512 da sua senha salgada. Você também gera um inteiro random 200. Em seguida, armazena os primeiros 200 bytes do sal, seguidos pelo hash de senha salgada, seguido pelo restante do sal.

Ao autenticar a input de senha de um usuário, seu aplicativo passará a cadeia e presumirá que o primeiro byte de 1 dos dados é o primeiro byte 1 do sal, seguido pelo hash salgado. Este passe falhará. O aplicativo continuará usando os primeiros 2 bytes dos dados como os primeiros 2 bytes do salt e repita até que um resultado positivo seja encontrado após usar os primeiros 200 bytes como os primeiros 200 bytes do salt. Se a senha estiver errada, o aplicativo continuará tentando todas as permutações até que nenhuma seja encontrada.

As vantagens desta abordagem:

Maior segurança – mesmo que sua lógica de autenticação seja conhecida, a lógica exata é desconhecida em tempo de compilation. É praticamente impossível realizar um ataque de força bruta, mesmo com o conhecimento da lógica exata. Comprimentos aumentados de sal aumentarão ainda mais a segurança.

Os contras desta abordagem:

Como a lógica exata é inferida em tempo de execução, essa abordagem exige muito da CPU. Quanto maior o comprimento do sal, mais intensiva a CPU se torna essa abordagem.

Autenticar senhas incorretas envolverá o maior custo de CPU. Isso pode ser contraproducente para solicitações legítimas, mas aumenta a segurança contra invasores.

Essa abordagem pode ser implementada de várias maneiras e pode ser ainda mais segura usando sais de largura variável e / ou hashes de senhas salgadas.

Muitas vezes, eles são anexados ao hash e armazenados no mesmo campo.

Não há necessidade de armazená-los separadamente – o objective é usar um sal random para cada senha, de modo que uma única tabela de arco-íris não possa ser usada contra todo o conjunto de hashes de senha. Com sais randoms, um invasor deve forçar brutalmente cada hash separadamente (ou calcular uma tabela de arco-íris para todos os sais possíveis – muito mais trabalho).

Se você tivesse um local de armazenamento mais seguro, faria sentido apenas armazenar os hashes lá.

Baseado no livro ASP.NET MVC 4 Web Applications de William Penberthy:

  1. Ter access aos sais armazenados em um database separado requer que hackers hackem dois bancos de dados diferentes para obter access ao sal e à senha salgada. Armazená-los na mesma tabela que a senha, ou até mesmo outra tabela do mesmo database, significaria que, quando os hackers obtivessem access ao database, teriam access ao hash do sal e da senha. Como a segurança inclui o processo de tornar o hacking no sistema muito caro ou demorado para valer a pena, dobrar a quantidade de access que um hacker teria que obter deveria tornar o sistema mais seguro.
  2. A facilidade de uso é a principal razão para manter os sais no mesmo database que as senhas em hash. Você não precisa garantir que dois bancos de dados estejam sempre disponíveis ao mesmo tempo e sempre em sincronia. A vantagem de ter um sal é mínima se cada usuário tiver um sal random, pois embora possa facilitar a descoberta da senha de um indivíduo, a quantidade de força necessária para quebrar as senhas do sistema em geral será alta. Nesse nível de discussão, é exatamente isso que a expectativa é: proteger as senhas. Se os hackers tiverem adquirido uma cópia do database, os dados do seu aplicativo já estarão comprometidos. Neste ponto, a questão é mitigar os riscos dos usuários devido ao potencial das senhas compartilhadas.
  3. O requisito de manter dois bancos de dados vinculados separados é extenso. Concedido, acrescenta a percepção de segurança, mas a única vantagem que dá é que ele protege uma senha, um único elemento de dados. Se cada campo do database fosse criptografado individualmente, e esse mesmo sal fosse usado para isso, faria mais sentido armazená-lo separadamente dos dados, porque a segurança básica do sistema é aprimorada.