Criptografia de senha efetiva

votos
12

Eu tomei um olhar para a questão StackOverflow, Layer senha de criptografia / banco de dados AES ou App Camada AES, e eu gostaria de hash forma eficaz e eficiente minhas senhas no registro (web app) e, em seguida, ser capaz de verificar que eles são corrigir no login. Eu estou usando VB, mas confortável usando C #.

Eu adoraria usar a classe de criptografia de Jeff Atwood descrito no .NET Encryption simplificado como é realmente fácil de entender. Ele tem uma classe, mas hashing Eu não tenho nenhuma idéia de como login e comparar hashes depois de terem sido hash. Esta é a demonstração de seus métodos de hash usando sua classe de criptografia de Jeff:

Sub DemoHash()
    Dim d As New Encryption.Data( _
        {ts '2004-10-09 08:10:04'}The world is beautiful and needs caring by its children)

    Dim hash As New Encryption.Hash(Encryption.Hash.Provider.SHA1)
    Dim hash2 As New Encryption.Hash(Encryption.Hash.Provider.SHA256)
    Dim hash3 As New Encryption.Hash(Encryption.Hash.Provider.SHA384)
    Dim hash4 As New Encryption.Hash(Encryption.Hash.Provider.SHA512)
    Dim hash5 As New Encryption.Hash(Encryption.Hash.Provider.MD5)
    Dim hash6 As New Encryption.Hash(Encryption.Hash.Provider.CRC32)

    hash.Calculate(d)
    hash2.Calculate(d)
    hash3.Calculate(d)
    hash4.Calculate(d)
    hash5.Calculate(d)

    Console.WriteLine(SHA1:    & hash.Value.Hex)
    Console.WriteLine(SHA256:  & hash2.Value.Hex)
    Console.WriteLine(SHA384:  & hash3.Value.Hex)
    Console.WriteLine(SHA512:  & hash4.Value.Hex)
    Console.WriteLine(MD5:     & hash5.Value.Hex)
    Console.WriteLine(CRC32:   & hash6.Calculate(d).Hex)
    Console.WriteLine()

    Dim salt As New Encryption.Data(salty!)
    Console.WriteLine(Salted CRC32:   & hash6.Calculate(d, salt).Hex)

    Console.WriteLine(Press ENTER to continue...)
    Console.ReadLine()
End Sub

Então, minhas perguntas são:

  1. I pode criptografar a senha (embora eu não tenho nenhuma intenção de armazená-lo) e botar uma corda. Se eu fosse para ter um usuário chamado 'Barry' com a senha 'fishlegs', qual é a melhor maneira de armazenar sua senha e recuperá-la?

  2. Em SQL Server; é nvarchar binário ou a melhor opção para o armazenamento do hash?

  3. Baseado em 'Barry' e sua senha o que efetivamente é o hash armazenar? É uma criptografia de 'fishlegs' anexadas a um sal?

A criptografia é difícil!

Graças a quem puder ajudar ...

Publicado 19/05/2009 em 16:13
fonte usuário
Em outras línguas...                            


8 respostas

votos
86

Hmm, eu acho que você está faltando apenas alguns conceitos básicos relacionados à forma como hashing funciona. Deixe-me tentar explicar brevemente. Vou começar simples e elaborada na minha resposta depois, portanto, leia a coisa toda, a informação no início não será segura.

O que você deseja usar para armazenar uma senha é uma função conhecida como um "one-way hash". O que isto significa é que, para qualquer entrada que você alimenta a função, a mesma entrada sempre vai dar o mesmo resultado. No entanto, não há nenhum processo matemático que permite tirar essa seqüência resultado e descobrir o que era a entrada original.

Vamos dar MD5 como um exemplo de uma função hash. Se eu executar MD5 na corda "password", eu sempre obter o resultado "5f4dcc3b5aa765d61d8327deb882cf99". No entanto, se você fosse simplesmente dar a alguém que resultam string ( "5f4d ..."), é impossível para eles para aplicar algum processo matemático para "inverter" a função e descobrir que ela veio de "password".

O que isto significa é que quando um usuário primeiro define a sua senha, você aplicar uma função hash para ele, e armazenar o resultado. Então, ao invés de armazenar "password", você armazenar "5f4dcc3b5aa765d61d8327deb882cf99". Então, quando o usuário tenta fazer login, você pegar o que digitou na caixa de senha no formulário de login, e aplicar a mesma função hash. Se você obter o mesmo resultado que o que está armazenado no banco de dados, que deve ter entrado a mesma senha como eles originalmente escolheu, mesmo que você não tem idéia do que isso senha original realmente era.

Agora, mesmo que seja impossível "reverter" uma função hash, o fato de que a mesma entrada sempre dá o mesmo resultado significa que alguém pode simplesmente construir um grande banco de dados de pares de entrada / saída, e usar isso para reverter efetivamente hashes. Isso é chamado de "rainbow table". Há muitos deles disponíveis na internet, por isso não é seguro usar hashing simples, apenas no caso de seu banco de dados nunca é comprometida. Isto é, mesmo que seja matematicamente impossível tomar "5f4dcc3b5aa765d61d8327deb882cf99" e descobrir o que ele veio correndo MD5 em "password", é muito fácil de determinar que, na prática. Tudo que você tem a fazer é executar cada palavra em um dicionário através de MD5 e armazenar os resultados, e você pode facilmente reverter senhas simples.

Este é o lugar onde "salga" entra. Se você gerar uma seqüência aleatória "sal" para cada usuário e anexar que a sua senha, ele efetivamente ruínas tabelas do arco-íris. Por exemplo, digamos que o mesmo usuário acima registra com sua senha como "password". Geramos um sal de 8 caracteres aleatórios para anexar a sua senha antes de hash-lo. Vamos dizer que é "A4BR82QX". Agora, em vez de hash "password", nós de hash "A4BR82QXpassword". Isto dá o resultado "87a4ba071c8bcb5efe457e6c4e6c4490", de modo que armazenar que no banco de dados, junto com a corda sal. Então, quando esse usuário tenta fazer login, em vez de hash e comparando a senha que eles entraram no formulário de login diretamente, tomamos o que eles entraram, colocar "A4BR82QX" na frente dele novamente, e hash que.

Efetivamente o que você fez aqui é fazer com que as tabelas pré-gerado do arco-íris são inúteis para tentar quebrar as senhas em seu banco de dados. Desde o sal é aleatória, e cada usuário tem um diferente (em geral), o atacante terá que voltar a gerar suas tabelas do arco-íris para cada usuário individual . Isso é muito mais difícil.

No entanto, há mais um problema, e é isso que a geração de hashes MD5 é rápido . Mesmo que salga como esta exige-los para voltar a gerar tabelas do arco-íris, por causa de como MD5 rápido é, algumas tabelas decentemente-completos do arco-íris pode ser criado muito rapidamente. Então, se eles só querem quebrar uma conta de alto valor em seu site, não é realmente um grande negócio para eles para passar algum tempo gerando tabelas do arco-íris para tentar reverter essa senha. Se senha original da conta de alto valor não era seguro o suficiente por si só, que ainda vai ser encontrada muito rapidamente, mesmo com a salga.

Então, o próximo passo é encontrar um lento função hash, e usar isso em vez de um rápido como MD5. Ter o seu site ter um par extra de segundos para verificar um início de sessão não é um grande negócio em tudo. Mas quando alguém está tentando gerar tabelas do arco-íris para quebrar uma senha, tendo cada entrada demorar alguns segundos é um assassino absoluta. Eu escrevi o suficiente aqui, então eu só vou terminar ligando a este artigo, que entra em muitos detalhes sobre a escolha de uma boa função hash lento: Chega com as tabelas do arco-íris: O Que Você Precisa Saber sobre esquemas de senha segura .

Essa foi uma resposta muito grande, se qualquer um que está claro, por favor me avise com um comentário e eu vou editar a elaborar.

Respondeu 19/05/2009 em 16:32
fonte usuário

votos
7

OK assim que um par de coisas sobre a classe de Jeff antes de tudo. SHA1 e MD5 são preteridos agora. CRC32 não é adequado a todos para senhas. Em segundo lugar você deve ser salga cada haxixe, de preferência com um valor diferente sal. Geralmente você escolher um bloco criptograficamente aleatória de dados para esta, mas em um impulso, você poderia usar o nome de usuário. Para sal que você prefixo ou sufixo o valor de sal em algum lugar no processo. I tendem a criptografar a senha, mistura o sal, combinar os dois, depois de hash novamente. Mas você pode trocar as coisas realmente não importa muito, contanto que você é consistente.

Então ao invés de confundir as coisas ainda mais com a classe de Jeff vamos fazer isso da maneira clássica.

Em primeiro lugar geração aleatória sal.

public static byte[] GetRandomSalt()
{
  int minSaltSize = 16;
  int maxSaltSize = 32;

  Random random = new Random();
  int saltSize = random.Next(minSaltSize, maxSaltSize);
  saltBytes = new byte[saltSize];
  RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
  rng.GetNonZeroBytes(saltBytes); 
  return saltBytes;
}

então hash

public static byte[] ComputeHash(string plainText)
{
  byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
  HashAlgorithm hash = new SHA256Managed();
  return hash.ComputeHash(plainTextWithSaltBytes);
}

Então, isso vai calcular um hash SHA256 e devolvê-lo como um array de bytes.

Se você estava salga você faria algo como o seguinte

byte[] passwordHash = ComputeHash(password);
byte[] salt = GetRandomSalt();
byte[] saltHash = ComputeHash(salt);

byte[] hashWithSaltBytes = new byte[hashBytes.Length + saltBytes.Length];
for (int i=0; i < hashBytes.Length; i++)
  hashWithSaltBytes[i] = hashBytes[i];
for (int i=0; i < saltBytes.Length; i++)
  hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

E então, se você está entediado de hash-lo novamente, ou deixar como está.

Para transformar uma matriz de bytes em uma string, se você não gosta de bytes de armazenagem que podem ser usados

string hashValue = Convert.ToBase64String(hashWithSaltBytes);

Comparação de strings são mais fáceis do que comparações de byte onde você tem que iterar sobre cada matriz, até você. Basta lembrar se você estiver usando sais aleatórios você precisa armazená-los ao lado da senha.

Respondeu 19/05/2009 em 16:39
fonte usuário

votos
6
  • Pegue a senha do usuário " Segredo! ".
  • Gerar um sal aleatório de alguns bytes " s4L75a1T ".
  • Concat-los para " s4L75a1TSecret! ".
  • Calcular o "hash de b9797a5b683804eb195b6ba2a5e368ae74394cd3 " (este é o SHA-1 em hexadecimal)
  • Armazenar o hash eo sal (tanto como string hexadecimal, corda Base64, ou o que quiser) no banco de dados juntamente com o nome de usuário ea outras informações do usuário (no exemplo, o sal é apenas uma seqüência simples e o hash é Base64 codificado ).
    Nome Sobrenome Sal Hash
    -------------------------------------------------- ---------------
    John Doe s4L75a1T uXl6W2g4BOsZW2uipeNornQ5TNM =

Se você quiser verificar a senha do usuário, basta levar o nome de usuário, procure o sal, fazer o acima novamente e veja se o hash calculado e um no jogo do banco de dados. Não há nenhuma maneira (conhecido) para (facilmente) recuperar a senha.

Respondeu 19/05/2009 em 16:23
fonte usuário

votos
4

Não confunda a criptografia de senhas com hash-los; com uma boa função hash de criptografia, você não deve ser capaz de reverter o processo de hashing para recuperar a string original.

A resposta de Chad acima é uma excelente explicação ponto-a-ponto dos conceitos envolvidos.

Este assunto tem sido feito até à morte em toda a Internet; não apenas no estouro de pilha; a sério - uma simples pesquisa na web deve encontrar-lhe um guia bastante abrangente.

Obrigado, Jeff, para espalhar ainda um outro monte de desinformação. Suponho que veremos uma enorme quantidade de perguntas equivocadas sobre hashing, criptografia, etc. durante a próxima semana, para não mencionar a porcaria que vai vir para cima sobre aritmética de ponto flutuante.

Respondeu 19/05/2009 em 16:18
fonte usuário

votos
3

O que você está essencialmente querendo fazer é:

A) Na criação da conta, você recebe um nome de usuário e senha do usuário, você botar aqueles juntamente com o seu próprio sal e armazenar a seqüência resultante em seu banco de dados como:

Dim sUserName = "barry"
Dim sPassWord = "fishlegs"
Dim mySalt = "A deliciously salty string! fillED WIth all KindS of Junkk(&^&*(£"
Dim d As New Encryption.Data(mySalt + sUserName + sPassWord)
Dim hash As New Encryption.Hash(Encryption.Hash.Provider.SHA256)
hash.Calculate(d)
Dim sTheSaltedHashedUnPassCombination = hash.Value.Hex;
SavenewPasswordHashToDatabase(sTheSaltedHashedUnPassCombination)

Você nunca armazenar sPassWord.

B) Quando o usuário efetuar login você executar exatamente a mesma operação sobre o nome de usuário e senha fornecidos em seguida, compare o hash resultante para o valor previamente armazenado no banco de dados para que você usar:

Dim sThePreviouslyCreatedHashFromTheDatabase = GetHashForUserFromDatabase(usernameProvided)
Dim mySalt = "A deliciously salty string! fillED WIth all KindS of Junkk(&^&*(£"
Dim d As New Encryption.Data(mySalt + usernameProvided+ passwordProvided)
Dim hash As New Encryption.Hash(Encryption.Hash.Provider.SHA256)
hash.Calculate(d)
Dim sTheSaltedHashedUnPassCombination = hash.Value.Hex;
if (sThePreviouslyCreatedHashFromTheDatabase.Equals(sTheSaltedHashedUnPassCombination))
    'UN & Password Valid!
else
    'UN & PW Invalid!
end

(Desculpem quaisquer erros, VB não é minha língua)

Para responder às suas perguntas dadas:

1) Ver acima. Nunca guarde a senha diretamente, armazenar o valor hash

2) usar um char (X), o número de caracteres devolvido a partir do hash é constante para que possa dar-lhe um tamanho de armazenamento conhecido.

3) O que você está efetivamente armazenar é a senha para o usuário salgado com seu nome de usuário e também salgado com a constante no seu servidor. Esta será uma cadeia de comprimento fixo e você não pode mudar essa string de volta para o nome de usuário e senha separado.

Respondeu 19/05/2009 em 16:33
fonte usuário

votos
3

Eu acredito que o processo é assim: Gerar um sal aleatório, então 'fishlegs' + 'r4nd0mS4lt' para obter 'fishlegsr4nd0mS4lt'. Então você hash que, digamos, com MD5 (embora você pode querer usar SHA256 para ser mais seguro) para obter: 593d5518d759b4860188158ef4c71f28. Guarde isso e o sal gerado aleatoriamente. Quando o usuário faz login, acrescente o sal aleatório e, em seguida, verificar se a sua palavra-passe introduzida com o sal corresponde o hash no banco de dados.

Respondeu 19/05/2009 em 16:20
fonte usuário

votos
2
  1. Todo o ponto de hashing é que você armazenar os hashes em vez das senhas em texto puro e não podem ser recuperados (pelo menos com grande dificuldade). Funções hash são projetados para ser one-way, de modo que a recuperação é impossível - esta é a sua própria essência.
  2. nchar[n]é provavelmente a melhor opção, uma vez que os algoritmos de hash comuns produzir resultados de comprimento constante ( SHA1 emite um hash de 160 bits). A prática comum é a de converter o hash para Base64 para que ele possa ser armazenado como texto ASCII.
  3. Um sal é apenas um método que acrescenta bits aleatórios para um hash de forma a complicar o processo de craqueamento. Cada bit extra de sal significa que um cracker de força bruta deve levar o dobro do tempo (e usar o dobro da memória).
Respondeu 19/05/2009 em 16:22
fonte usuário

votos
0

ASP.NET inclui um SQL baseado provedor de associação que lhe permite criar, armazenar e verificar encryped ou senhas com hash , sem que você precise fazer nada - como diz Eric Lippert:

deixe-me dar-lhe todo o meu cuidado padrão sobre rolar seus próprios algoritmos de criptografia e sistemas de segurança: não.

Respondeu 23/05/2009 em 00:14
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more