Criptografia de senha no lado do cliente

Duplicar Possível:
Sobre o sistema de hashing de senha no lado do cliente

Eu tenho que proteger as senhas dos meus usuários do site. O que fiz foi usar o hash de criptografia MD5 no lado do servidor. Mas o problema é que as senhas permanecem em texto simples até chegar ao servidor, o que significa que a senha pode ser capturada usando o monitoramento de tráfego. Então, o que eu quero é usar um mecanismo de criptografia / hashing de senha do lado do cliente e enviar a senha criptografada / hash. Alguém pode dizer qual é a maneira de fazer isso?

Isso não será seguro e é simples explicar por quê:

Se você hash a senha no lado do cliente e usar esse token em vez da senha, não será provável que um invasor descubra qual é a senha.

Mas o atacante não precisa descobrir qual é a senha, porque o servidor não está mais esperando a senha – ela está esperando o token. E o invasor conhece o token porque está sendo enviado por HTTP não criptografado!

Agora, pode ser possível hackear algum tipo de forma de desafio / resposta de criptografia, o que significa que a mesma senha produzirá um token diferente para cada solicitação. No entanto, isso exigirá que a senha seja armazenada em um formato descriptografável no servidor, algo que não é ideal, mas pode ser um compromisso adequado.

E, por fim, você realmente deseja exigir que os usuários tenham o JavaScript ativado antes de fazer login no seu site?

Em qualquer caso, o SSL não é uma solução cara ou especialmente difícil de configurar

Você precisa de uma biblioteca que possa criptografar sua input no lado do cliente e transferi-la para o servidor de forma criptografada.

Você pode usar as seguintes libs:

  • j Criptografia . Criptografia assimétrica cliente-servidor em Javascript

Atualização após 3 anos:

  • Stanford Javascript Crypto Library

Atualização após 4 anos (Wohoo!)

  • CryptoJS – Criptografia fácil de usar
  • ForgeJS – praticamente cobre tudo

Ainda não está convencido? Nem eu 🙂

  • OpenPGP.JS – Coloque o formato OpenPGP em todos os lugares – executa em JS para que você possa usá-lo em seus aplicativos da web, aplicativos móveis e etc.

Eu escolheria essa solução simples .

Resumindo:

  • Cliente “Eu quero fazer o login”
  • Servidor gera um número random #S e envia para o cliente
  • Cliente
    • lê nome de usuário e senha typescripts pelo usuário
    • calcula o hash da senha, obtendo h(pw) (que é o que está armazenado no database)
    • gera outro número random #C
    • concatena h(pw) + #S + #C e calcula seu hash, chame de h(all)
    • envia para o username do servidor, #C e h(all)
  • Servidor
    • recupera h(pw)' para o username especificado, do database
    • agora tem todos os elementos para calcular h(all') , como o cliente fez
    • se h(all) = h(all') então h(pw) = h(pw)' , quase certamente

Ninguém pode repetir a solicitação para efetuar login como o usuário especificado. #S adiciona um componente variável ao hash, a cada vez (é fundamental). #C adiciona mais ruído nele.

Esse tipo de proteção é normalmente fornecido usando HTTPS , para que toda a comunicação entre o servidor da Web e o cliente seja criptografada.

As instruções exatas sobre como conseguir isso dependerão do seu servidor web.

A documentação do Apache possui um guia HOW-TO de Configuração SSL que pode ser de alguma ajuda. (graças ao usuário G. Qyy pelo link)

Eu listei um JavaScript completo para criar um MD5 na parte inferior, mas é realmente inútil sem uma conexão segura por vários motivos.

Se você tiver a senha MD5 e armazenar o MD5 em seu database, o MD5 será a senha. As pessoas podem dizer exatamente o que está no seu database. Você basicamente transformou a senha em uma string mais longa, mas ela ainda não é segura se é isso que você está armazenando no database.

Se você disser: “Bem, eu vou MD5 o MD5” você está perdendo o ponto. Observando o tráfego da rede ou procurando em seu database, posso falsificar seu site e enviá-lo ao MD5. Concedido isso é muito mais difícil do que apenas reutilizar uma senha de texto simples, mas ainda é uma falha de segurança.

Acima de tudo, embora você não possa salgar o lado hash do cliente sem enviar o sal sobre a ‘rede não-criptografada, tornando a salga inútil. Sem um sal ou com um sal conhecido, eu posso atacar o hash com força bruta e descobrir qual é a senha.

Se você for fazer esse tipo de coisa com transmissões não criptografadas, precisará usar uma técnica de criptografia de chave pública / chave privada . O cliente criptografa usando sua chave pública, em seguida, você descriptografa em seu final com sua chave privada, em seguida, você MD5 a senha (usando um usuário único sal) e armazená-lo em seu database. Aqui está uma biblioteca de chave pública / privada GPL em JavaScript .

De qualquer forma , aqui está o código JavaScript para criar um lado do cliente MD5 (não meu código):

 /** * * MD5 (Message-Digest Algorithm) * http://www.webtoolkit.info/ * **/ var MD5 = function (string) { function RotateLeft(lValue, iShiftBits) { return (lValue<>>(32-iShiftBits)); } function AddUnsigned(lX,lY) { var lX4,lY4,lX8,lY8,lResult; lX8 = (lX & 0x80000000); lY8 = (lY & 0x80000000); lX4 = (lX & 0x40000000); lY4 = (lY & 0x40000000); lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF); if (lX4 & lY4) { return (lResult ^ 0x80000000 ^ lX8 ^ lY8); } if (lX4 | lY4) { if (lResult & 0x40000000) { return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); } else { return (lResult ^ 0x40000000 ^ lX8 ^ lY8); } } else { return (lResult ^ lX8 ^ lY8); } } function F(x,y,z) { return (x & y) | ((~x) & z); } function G(x,y,z) { return (x & z) | (y & (~z)); } function H(x,y,z) { return (x ^ y ^ z); } function I(x,y,z) { return (y ^ (x | (~z))); } function FF(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function GG(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function HH(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function II(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function ConvertToWordArray(string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWords_temp1=lMessageLength + 8; var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64; var lNumberOfWords = (lNumberOfWords_temp2+1)*16; var lWordArray=Array(lNumberOfWords-1); var lBytePosition = 0; var lByteCount = 0; while ( lByteCount < lMessageLength ) { lWordCount = (lByteCount-(lByteCount % 4))/4; lBytePosition = (lByteCount % 4)*8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<>>29; return lWordArray; }; function WordToHex(lValue) { var WordToHexValue="",WordToHexValue_temp="",lByte,lCount; for (lCount = 0;lCount<=3;lCount++) { lByte = (lValue>>>(lCount*8)) & 255; WordToHexValue_temp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2); } return WordToHexValue; }; function Utf8Encode(string) { string = string.replace(/\r\n/g,"\n"); var utftext = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } return utftext; }; var x=Array(); var k,AA,BB,CC,DD,a,b,c,d; var S11=7, S12=12, S13=17, S14=22; var S21=5, S22=9 , S23=14, S24=20; var S31=4, S32=11, S33=16, S34=23; var S41=6, S42=10, S43=15, S44=21; string = Utf8Encode(string); x = ConvertToWordArray(string); a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; for (k=0;k 

Você marcou essa questão com a tag ssl e o SSL é a resposta. Curioso.

Você também pode simplesmente usar a autenticação http com o Digest ( aqui algumas infos se você usar o Apache httpd , Apache Tomcat e aqui uma explicação do digest ).

Com o Java, para informações interessantes, dê uma olhada em:

  • Noções básicas sobre autenticação de logon
  • Exemplos de solicitação e resposta de autenticação de resumo HTTP
  • Problemas de autenticação HTTP
  • Autenticação Básica Para JSP Page (não é digerir, mas acho que é uma fonte interessante)

Existem bibliotecas MD5 disponíveis para javascript. Lembre-se de que essa solução não funcionará se você precisar oferecer suporte a usuários que não possuem JavaScript disponível.

A solução mais comum é usar HTTPS. Com HTTPS, a criptografia SSL é negociada entre seu servidor da Web e o cliente, criptografando todo o tráfego de maneira transparente.

Para uma situação semelhante, usei este PKCS # 5: Padrão de Criptografia Baseada em Senha dos laboratórios RSA. Você pode evitar o armazenamento da senha, substituindo-a por algo que só pode ser gerado a partir da senha (em uma frase). Existem algumas implementações JavaScript.