Segurança - Parte 2 - Hash em senhas

Antes de armazenar ou utilizar uma senha ela deve ser hasheada. Mas não de qualquer jeito, nem com qualquer algoritimo. Veja nessa segunda parte como hasear a senha antes de armazenar e o porquê.

O propósito do hash

A principio um hash é uma função que a partir de um texto o transforma em outro texto truncado. Chamado hash (ou digest).

Hash são algoritimos one-way. Não é possivel reverter o seu resultado. São determinísticos. Dada uma certa entrada, ela produzirá sempre a mesma saída.

Na parte 1 mostrei porque fazer hash do password é uma boa prática. Ao fazer hash da senha e salvar o digest é como uma segunda linha de defesa. O repositório foi comprometido, mas o atacante não terá acesso fácil a senha do usuário.

Se você ainda não leu a primeira parte, sugiro a leitura. Segurança - Parte 1 - Como armazenar senhas

Por que não MD5, SHA-* (SHA1, SHA2) etc?

Elas são funções hash de uso geral. Projetadas para gerar o Digest de uma quantidade enorme de dados no menor tempo possível. Isso significa que eles são fantásticos para garantir a integridade dos dados. Mas são horriveis para armazenar senhas. Veja abaixo como é relativamente simples quebrar uma senha utilizando esses algoritimos de hash.

Brute force attack

Uma maquina moderna. 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. Isso é o resultado de um computador caseiro usado no dia a dia.

Se você investir um pouco e montar um pequeno super computador, você pode gerar cerca de 700.000.000 de senhas por segundo. Veja o resultado desta pesquisa aqui.

Assim você pode quebrar um password mediano testando todas as possiveis combinações em menos de 1 segundo.

Dictionary attack

A técnica do brute force pode ser refinada através de um dictionary attack. Que consiste em uma lista de palavras. Essa lista pode ser um as senhas mais comums. Ou então um dicionario com todas as senhas de outros bancos já vazados. Aprimorando o ataque.

UM SALT NÃO VAI TE PROTEGER

Salts são inúteis para impedir dictionary ou brute force attacks. Você pode usar salts enormes. O salt não afeta a rapidez com que um invasor pode tentar uma senha. Considerando que o hash e o salt estão no teu repositório. Serão inúteis.

Salt é besteira?

Não. O salt vai proteger de ataques como Rainbow table, forçando o atacante a re-computar os passwords com o Salt. Bloqueando o parelelismo. Em outro post irei abordar a utilização de salt e seus beneficios.

O algoritimo deve ser lento

Em contraste com os algoritimos anteriores que foram desenvolvidos para serem performaticos. Os algoritimos de hash de senha foram projetados para serem lentos.

Lembre-se que o hash é uma segunda linha de defesa. O invasor já passou pela primeira. Logo para ele passar por essa defesa vai precisar de um super computador.

Os hash de senha devem usar tantos recursos quanto possível para tornar os ataques de força bruta mais lentos e mais caros.

Argon2, bcrypt e scrypt - PBKDF2

Abaixo uma descrição sobre esses três algoritimos de hash.

Bcrypt

O bcrypt é uma variação do algoritimo Blowfish e introduziu o work factor. Ele não apenas inclui salts, mas também torna os ataques de força bruta substancialmente mais difíceis. O bcrypt é considerado "CPU-hardned". O que significa que calcular um hash requer mais esforço da CPU. É possivel definir o número de iterações usando um worker factor. O que torna ainda mais difícil a força bruta. À medida que os computadores ficam mais rápidos e os recursos de computação se tornam mais baratos, você pode simplesmente aumentar o worker factor para aumentar o consumo de recursos.

Scrypt

O scrypt é uma função "CPU-hardned", mas também tem a vantagem de ser "Memory-hard". Ele consume não apenas a CPU como também utiliza mais mais recursos de memória.

Argon2

Argon2 adiciona uma terceira dimensão de complexidade e custo: o número de threads usados para calcular o hash.

Os invasores precisam ter não apenas uma grande quantidade de recursos de computação e memória disponíveis, mas também mais núcleos de CPU físicos. O que torna os ataques de força bruta substancialmente mais caros para serem executados.

PBKDF2

O ASP.NET Identity utiliza o PBKDF2 com HMAC-SHA256, um Salt de 128 bit e uma sub chave de 256 bit. E por padrão 10.000 iterações. PBKDF2 já foi considerada "ok" e há quem diga que nem de perto é uma boa decisão. Por sorte isso pode ser alterado. Em outro artigo falaremos sobre isso!

Qual algoritmo de Hash utilizar?

Argon2Id. É quase unânime entre especialistas. Foi o vencedor do Concurso Password Hashing Competition em julho de 2015. Há muitos modos, incluindo Argon2d, Argon2i, Argon2id, cada um com objetivos específicos.

Segundo a documentação:

Argon2d uses data-dependent memory access, which makes it suitable for cryptocurrencies and proof-of-work applications with no threats from side-channel timing attacks. Argon2i uses data-independent memory access, which is preferred for password hashing and password-based key derivation. Argon2id works as Argon2i for the first half of the first iteration over the memory, and as Argon2d for the rest, thus providing both side-channel attack protection and brute-force cost savings due to time-memory tradeoffs.

A implementação do Argon2id é a considerada ideal para hash de senhas. O OWASP simplesmente recomenda Argon2.

O IETF recomenda que "se você não souber a diferença, […] escolha Argon2id".

If you do not know the difference between them or you consider side-channel attacks as viable threat, choose Argon2id

Playground

Quer saber como é a hash do bcrypt, scrypt e argon2? Acesse essa ferramenta online:

Conclusão

Use Argon2id. Deu para perceber que que autenticação, senhas. Não é trivial. Se a senha do teu usuário vazar pode gerar danos incálculaveis. Desde prejuizos financeiros até prejuizos a imagem dele. Lidar com senhas exige extrema responsabilidade.

Na primeira parte disse que a mehor opção não é criar um sistema de autenticação. Um sistema de autenticação feito por amadores. É um sistema de autenticação amador.

Na próxima parte, irei falar sobre como melhorar a segurança das senhas com ASP.NET Identity.

Referências