Provavelmente, o senhor está armazenando as senhas de forma incorreta

A Web é um labirinto de contas de usuário e logins. Quase todos os lugares que o senhor vai na Web exigem mais um novo conjunto de credenciais. O login unificado parece estar nos escapando no momento, portanto, o status quo é uma explosão de nomes de usuário e senhas para cada usuário. Como consequência de todos esses dados de identidade do usuário em silos, o Facebook e a maioria dos outros aplicativos da Web nos incentivam a distribuir nossas credenciais como se fossem doces de Halloween, como observa Dare Obasanjo:

No Facebook, há uma opção para importar contatos do Yahoo! Mail, Hotmail, AOL e Gmail, o que exige que eu insira meu nome de usuário e senha desses serviços no site deles. Toda vez que faço login no Yahoo! Mail, há um aviso que me pede para importar meus contatos de outros serviços de e-mail, o que exige que eu forneça minhas credenciais desses serviços também.

Essa é uma situação deplorável. Estamos ensinando aos usuários que suas credenciais têm pouco valor e devem ser entregues livremente a qualquer site que lhes agrade. É um hábito incrivelmente perigoso para inculcar nos usuários; isso faz com que eles muito mais vulneráveis ao phishing:

Se os usuários se sentirem à vontade para inserir suas credenciais em todos os tipos de lugares aleatórios, isso os tornará mais suscetíveis a ataques de phishing. Esse é um dos motivos pelos quais serviços como o Meebo são preocupantes para mim.

O último coisa que deveríamos estar fazendo é encontrar maneiras de tornar o phishing mais poderoso. O phishing é um exploit de engenharia social tão atemporal, tão eficaz e tão poderoso que eu o chamo de o hack eterno. A tabela Rainbow e os ataques de força bruta podem ser derrotados por meio do uso criterioso da tecnologia. O phishing não pode.

encontre seus amigos no facebook

Os usuários colecionam nomes de usuário e senhas como fazem com o Pokemon. É uma situação lamentável, mas, para o bem ou para o mal, é assim que as coisas são. Nós, como desenvolvedores de software, temos a responsabilidade de armazenar todos esses nomes de usuário e senhas em algum tipo de banco de dados. No momento em que armazenamos a senha de um usuário, assumimos a responsabilidade de protegê-latambém. Digamos que um hacker, de alguma forma, obtenha uma lista de todos os nossos nomes de usuário e senhas. Ou foi um trabalho interno de alguém que tinha acesso ao banco de dados, ou o banco de dados foi acidentalmente exposto à Web pública. Não importa como. Simplesmente aconteceu.

Mesmo que os hackers tenham nossa tabela de nome de usuário e senha, estamos protegidos, certo? Tudo o que eles verão são os valores de hash. Somente os desenvolvedores mais grosseiramente incompetentes realmente armazenar senhas como texto simples no banco de dados, certo? Certo?

Recentemente, o pessoal por trás do Reddit.com confessou que uma cópia de backup de seu banco de dados havia sido roubada. Mais tarde, spez, um dos desenvolvedores do Reddit, confirmou que o banco de dados continha informações sobre as senhas dos usuários do Reddit e que essas informações estavam armazenadas em texto simples e desprotegido. Em outras palavras, uma vez que o ladrão tinha o banco de dados, ele também tinha as senhas de todos.

Errado.

Sou apenas um desenvolvedor de Windows que respira pela boca, não um da elite Y-combinando Lisp, oops, Python trabalhando no Reddit. E até eu sei que não é assim.

O senhor pode pensar que é relativamente sem importância se a senha do fórum de alguém for exposta como texto simples. Afinal, o que um invasor vai fazer com credenciais de fórum ruins? Postar mensagens irritadas em nome do usuário? Mas o a maioria dos usuários tende a reutilizar as mesmas senhasprovavelmente porque não conseguem se lembrar das duas dúzias de nomes de usuário e senhas exclusivos que são obrigados a ter. Portanto, se o senhor obtiver a senha do fórum deles, é provável que também tenha a senha de algo muito mais perigoso: o banco on-line e o PayPal.

Meu objetivo aqui não é arrastar o bom nome dos desenvolvedores do Reddit para a lama. Todos nós somos culpados. Tenho certeza de que todos os desenvolvedores que estão lendo isso já armazenaram senhas em texto simples em algum momento de suas carreiras. Eu sei que sim. Esqueça a culpa. O importante é ensinar aos nossos colegas que armazenar senhas em texto simples no banco de dados é estritamente proibido – que há uma maneira melhor, começando com hashes básicos.

O hashing das senhas evita a exposição do texto simples, mas também significa que o senhor será vulnerável ao ataque surpreendentemente eficaz da tabela arco-íris que documentei na semana passada. Os hashes sozinhos são melhores do que o texto simples, mas o mal. Isso não é suficiente para impedir um invasor determinado. Felizmente, a kryptonita para ataques à rainbow table é bastante simples: adicione um valor de sal aos hashes para torná-los exclusivos. Dei um exemplo de um hash salgado em minha postagem original:

hash = md5('deliciously-salty-' + password)

Mas IANAC – I Am Not A Cryptographer. Eu quis dizer isso apenas como um exemploe não como código de produção que o senhor deve copiar e colar naquela solução bancária empresarial extremamente popular em que está trabalhando. Na verdade, eu o extraí quase que diretamente do excelente post de Rich Skrenta sobre Usando hashes MD5 como funções utilitárias.

Thomas Ptacek, por outro lado, é um criptógrafo, e o ele tem um problema com minha escolha de técnicas de salga.

O que aprendemos? Aprendemos que, se estivermos em 1975, o senhor pode incendiar a ARPANet com ataques de rainbow table. Se estivermos em 2007, e os ataques à tabela arco-íris incendiarem a ARPANet, aprendemos que o senhor deve voltar a 1975 e esperar 30 anos antes de tentar projetar um esquema de hashing de senhas.*

Aprendemos que, se aprendemos alguma coisa com essa publicação no blog, deveríamos consultar nossos amigos e vizinhos da área de segurança para obter ajuda com nossos esquemas de senha, porque ninguém vai descobrir os bugs de game-over em nossos esquemas MD5 até que o número do cartão de crédito da minha mãe esteja sendo negociado em uma banca de rua em Tallinn, na Estônia.

Aprendemos que, em um esquema de hashing de senha, a velocidade é o inimigo. Aprendemos que o MD5 foi projetado para ser rápido. Portanto, aprendemos que o MD5 é o inimigo. Também Jeff Atwood e Richard Skrenta.

Por fim, aprendemos que, se quisermos armazenar senhas com segurança, temos três opções razoáveis: O esquema MD5 da PHK, o esquema Bcrypt da Provos-Maziere e o SRP. Aprendemos que a escolha correta é o Bcrypt.

* Nota do editor: Não é bem verdade. A maioria dos softwares “modernos” não usa um esquema de senha moderno. Windows XP/2000/NT, phpBB, a maioria dos esquemas de senha personalizados; todos vulneráveis a ataques de pré-computação da tabela rainbow.

Em resumo, se estivermos armazenando senhas, provavelmente estamos armazenando essas senhas incorretamente. Se isso não for óbvio até agora, a criptografia é difícile as chances de acertarmos sozinhos são basicamente nulas. É por isso que devemos confiar nas estruturas existentes e nos conselhos de especialistas como Thomas. Que maior elogio existe do que o de seu inimigo declarado?

Vamos recapitular:

  1. Não invente seu próprio esquema “inteligente” de armazenamento de senhas. Eu sei, o senhor é inteligente e entende de criptografia. Mas por essa porta passa a loucura… e o senhor sabe disso. abominações como o LMHash que têm ramificações de segurança contínuas e mundiais com as quais ainda estamos lidando hoje. Aproveite as ferramentas de armazenamento de senhas que sua estrutura oferece, pois elas provavelmente serão muito mais bem testadas e comprovadas do que qualquer esquema maluco que o senhor e sua equipe possam inventar por conta própria. As vulnerabilidades de segurança, ao contrário dos bugs de funcionalidade em seu aplicativo, são profundas e silenciosas. Elas podem ficar adormecidas por anos.
  2. Nunca armazene senhas como texto simples. Isso parece segurança 101 e é completamente óbvio em retrospecto. Mas nem todo mundo sabe o que o senhor sabe – basta perguntar ao Reddit. Armazene os hashes, nunca as senhas reais. Eduque seus colegas desenvolvedores.
  3. Adicione um sal aleatório longo e exclusivo a cada senha que armazenar. O objetivo de um salt (ou nonce, se preferir) é tornar cada senha única e longa o suficiente para que os ataques de força bruta sejam uma perda de tempo. Assim, a senha do usuário, em vez de ser armazenada como o hash de “myspace1”, acaba sendo armazenada como o hash de 128 caracteres de uma cadeia unicode aleatória + “myspace1”. Agora o senhor está completamente imune ao ataque da tabela rainbow.
  4. Use um hash criptograficamente seguro. Acho que o Thomas odeia tanto o MD5 que faz com que ele pareça um pouco mais louco do que realmente é. Mas ele está certo. O MD5 é vulnerável. Por que escolher algo remotamente vulnerável quando não é necessário? SHA-2 ou Bcrypt seria uma escolha melhor.

Obviamente, nada disso garante que o senhor conseguirá impedir que alguém deduza que A senha da conta do Myspace de Joe User é “myspace1”.

Mas quando o fizerem, pelo menos não será o senhor culpa.