Vale a pena hash senhas no lado do cliente


132

Quando quero implantar um sistema de login, sempre comparo o MD5 da senha fornecida com seu valor na tabela de usuários no lado do servidor.

No entanto, um amigo meu me disse que uma senha "limpa" poderia ser detectada por um software de rede.

Então, minha pergunta é: é uma boa idéia hash a senha no lado do cliente? É melhor do que fazer hash no lado do servidor?


1
Eu estava pensando em colocar a senha no lado do cliente, mas apenas para ter certeza de que a senha do cliente nunca existe como texto não criptografado no servidor, o que significa que eles podem se sentir mais fáceis sabendo que eu não sei a senha real ou não pode desistir facilmente se comprometido. eu sou louco?
Cyclone

1
Apenas por questões de integridade, já que estamos falando de segurança, e o MD5 foi mencionado no OP: deve-se sempre usar um salt ao criptografar uma senha. Usar MD5 simples e sem sal é um pouco melhor do que armazenar senhas de texto sem formatação no banco de dados.
Sffc

1
O @Cyclone Hashing SOMENTE no lado do cliente é definitivamente uma má ideia, pois se o invasor de alguma forma conhecer o hash, ele poderá usá-lo para fazer login como se soubesse a senha, ignorando o código de hash do lado do cliente.
Teejay

5
@Teejay: É por isso que você não envia o hash de forma clara. O servidor envia um salt aleatório para o cliente, você acrescenta o hash da senha e faz o hash novamente, depois envia de volta ao servidor que faz o mesmo cálculo. Um ataque de repetição falha porque o sal irá ser diferente
MSalters

2
Esta questão não deveria terminar em security.stackexchange.com?
Efr4k 31/05

Respostas:


115

Basicamente, seu amigo está certo. Mas simplesmente fazer o hash da senha no lado do cliente é apenas melhor do que enviá-la como texto sem formatação para o servidor. Alguém que pode escutar suas senhas de texto simples certamente também pode escutar senhas com hash e usar esses hashes capturados para se autenticar no servidor.

Por esse motivo, protocolos de autenticação mais seguros geralmente passam por vários ciclos para garantir que um ataque de repetição não funcione, geralmente, permitindo que o cliente selecione um monte de bits aleatórios, que são divididos em hash junto com a senha e também enviado de forma clara ao servidor.

No servidor:

  • gerar alguns bits aleatórios
  • envie esses bits (em texto não criptografado) para o cliente

No cliente:

  • gerar alguns bits aleatórios
  • concatenar senha, bits aleatórios do servidor e bits aleatórios do cliente
  • gerar hash do acima
  • envie bits aleatórios (em texto não criptografado) e hash ao servidor

Como o servidor conhece suas próprias informações aleatórias, bem como os bits aleatórios do cliente (os obteve como texto não criptografado), ele pode executar essencialmente a mesma transformação. Esse protocolo garante que ninguém que esteja ouvindo essa conversa possa usar as informações posteriormente para autenticar falsamente as informações gravadas (a menos que um algoritmo muito fraco tenha sido usado ...), desde que ambas as partes gerem "bits de ruído" diferentes a cada vez, o aperto de mão é realizado.

Editar Tudo isso é propenso a erros e tedioso e um pouco difícil de corrigir (leia-se: seguro). Se possível, considere o uso de implementações de protocolo de autenticação já escritas por pessoas conhecedoras (ao contrário de mim! O texto acima é apenas da memória de um livro que li há algum tempo.) Você realmente não deseja escrever isso normalmente.


5
Como ele pode se autenticar com a senha com hash no sistema de login, pois ela será novamente com hash?
Zakaria

4
Se você armazenar suas senhas no formato hash no servidor (como deveria), o cliente terá que hash a senha duas vezes: primeiro, somente a senha, para que corresponda à visão de mundo do servidor e, em seguida, conforme descrito acima para por causa do protocolo.
Dirk

3
@Dirk, como o atacante pode farejar nos dois sentidos, os "bits aleatórios" seriam farejados. Em seguida, o invasor pode analisar (ler: força bruta) o par de solicitação e resposta offline para encontrar a senha original.
Pacerier 18/07/12

7
No entanto, com a finalidade de enviar uma senha ou o hash de uma senha, geralmente um processo assimétrico como o Diffie-Hellman é usado para estabelecer uma chave de criptografia que permite que ambos os lados troquem informações sem que uma pessoa bisbilhoteira possa decifrá-la. É exatamente isso que o SSL faz e é o motivo pelo qual a maioria dos sites tem sua página de login em HTTPS / SSL. O SSL já protege contra ataques de repetição. Eu recomendaria aproveitar o SSL em vez de criar seu próprio protocolo. Embora eu concorde com salgar + hash a senha do lado do cliente, envie-a através de uma conexão SSL estabelecida.
AaronLS

14
Só para esclarecer: se você não estiver usando HTTPS, não importa qual javascript você executa no cliente; um MITM poderá modificar o conteúdo da sua página antes que ela atinja o cliente. HTTPS é a única solução.
Aidan

60

Primeiro de tudo, isso NÃO melhora a segurança do seu aplicativo (supondo que seja um aplicativo da web).

Use SSL (ou, na verdade, TLS, que é comumente chamado de SSL), não é muito caro (avalie o tempo que você está usando para encontrar maneiras de contorná-lo e multiplicá-lo pelo salário mínimo, a compra de um certificado ganha quase sempre).

O porquê disso é simples. O TLS resolve um problema (quando usado com certificados comprados, não autoassinado) que é bastante grande em criptografia: como sei se o servidor com o qual estou falando é o servidor com o qual acho que estou falando? Os certificados TLS são uma maneira de dizer: "Eu, a autoridade de certificação, confiável pelo seu navegador, certifica que o site em [url] possui essa chave pública, com uma chave privada correspondente, que (chave privada) somente o servidor conhece, procure Eu assinei minha assinatura em todo o documento, se alguém a alterou, você pode ver ".

Sem o TLS, qualquer criptografia se torna inútil, porque se eu me sentar ao seu lado em uma cafeteria, posso fazer seu laptop / smartphone pensar que sou o servidor e o MiTM (Man in the Middle) você. Com o TLS, seu laptop / smartphone gritará "CONEXÃO NÃO CONFIÁVEL", porque não tenho um certificado assinado pela autoridade de certificação que corresponda ao seu site. (Criptografia x autenticação).

Isenção de responsabilidade: os usuários tendem a clicar com o botão direito através destes avisos: "Conexão não confiável? O quê? Eu só quero minhas fotos de gatinhos! Adicionar exceção Clique em Confirmar Clique YAY! Gatinhos!"

No entanto, se você realmente não deseja comprar um certificado, ainda implemente o hash javascript do lado do cliente (e use a biblioteca standford (SJCL) para isso, NUNCA IMPLEMENTAR CRIPTO A MESMO ).

Por quê? Reutilização de senha! Posso roubar o cookie da sua sessão (o que me permite fingir ao seu servidor que sou você) sem HTTPS facilmente (consulte firesheep). No entanto, se você adicionar um javascript à sua página de login que, antes de enviar, faça hash na sua senha (use o SHA256, ou melhor ainda, use o SHA256, envie uma chave pública que você gerou e depois criptografe o hash da senha com isso, você não poderá usar salt) com isso) e envia a senha com hash / criptografada para o servidor. REHASH o hash no seu servidor com um salt e compare com o que está armazenado no seu banco de dados (armazene a senha assim:

(SHA256(SHA256(password)+salt))

(salve o salt como texto simples também no banco de dados)). E envie sua senha assim:

RSA_With_Public_Key(SHA256(password))

e verifique sua senha assim:

if SHA256(RSA_With_Private_Key(SHA256(sent_password))+salt_for_username) == stored_pass: login = ok

Porque, se alguém estiver farejando seu cliente, ele poderá fazer login como seu cliente (sequestro de sessão), mas NUNCA verá a senha de texto sem formatação (a menos que altere seu javascript, no entanto, um hacker da starbucks provavelmente não saberá como se interessar .) Assim, eles terão acesso ao seu aplicativo da web, mas não ao e-mail / facebook / etc. (para os quais seus usuários provavelmente usarão a mesma senha). (O endereço de e-mail será o nome de login ou será encontrado em seu perfil / configurações no seu aplicativo da web).


Eu acho que essa é uma boa resposta, mas provavelmente precisa de mais informações sobre como salgar corretamente e que é melhor usar uma função de hash "lento" antes de armazenar a senha no servidor (como bcrypt).
Neyt 23/11

24

É provável que você não se preocupe com isso - como Dirk menciona, mesmo que você faça o hash das senhas que um usuário mal-intencionado pode estar em uma rede e veja o hash ser enviado, e pode simplesmente enviar o mesmo hash.

É um pouco melhor, pois evita que o usuário mal-intencionado saiba qual é a senha, mas como ainda pode efetuar login (ou potencialmente reconstruir a senha original ), isso não ajuda.

Em geral, se você estiver preocupado com a segurança das senhas e dos dados do usuário (e deveria estar!), Convém usar um servidor SSL seguro. Se isso não for uma preocupação para você, por qualquer motivo, você também não deve se preocupar com hash; é apenas segurança através da obscuridade .


Editar em agosto de 2014: o Google está pressionando cada vez mais os sites a mudarem para HTTPS em todos os lugares , porque proteger a comunicação em si é a única maneira de impedir ataques de sniffing na rede. Tentativas de ofuscar os dados transmitidos apenas atrapalham, não param, um invasor dedicado e podem dar aos desenvolvedores uma falsa sensação de segurança perigosa.


Eu acho que sua opinião de que o hash no cliente é apenas "um pouco melhor" é verdadeira se você estiver focado apenas em obter xa senha do usuário e acessar um único serviço. Se você considerar o efeito coletivo, eu diria que é "muito melhor"; porque impede a criação de grandes bancos de dados de pesquisa de senhas usadas para fazer força bruta com hashes salgados em vários serviços. IMO. Veja o que o AWS Cognito faz no cliente para referência.
F1lt3r

17

Na verdade, eu discordo que o hash do lado do cliente é mais seguro nesse caso. Eu acho que é menos seguro.

O ponto principal de armazenar um hash da senha no banco de dados, em oposição à senha real (ou mesmo uma senha criptografada), é que é matematicamente impossível obter a senha original de um hash (embora seja teoricamente possível obter uma colisão entrada de hash, cuja dificuldade depende da força de segurança do algoritmo de hash). O possível vetor de ataque aqui é que, se um invasor em potencial comprometer seu banco de dados de armazenamento de senhas, ele / ela ainda não poderá obter as senhas originais de seus usuários.

Se o seu mecanismo de autenticação enviar um hash da senha, nesse cenário de violação de segurança, o invasor não precisará saber a senha real - eles apenas enviarão o hash que possuem e, e pronto, terão acesso a uma conta de usuário específica, e, por extensão, todo o seu sistema. Isso derrota completamente o ponto de armazenar uma senha com hash em primeiro lugar!

A maneira realmente segura de fazer isso é enviar ao cliente uma chave pública única para que ele criptografe a senha e, em seguida, você a descriptografa e re-hash no lado do servidor.

A propósito, esse tipo de pergunta provavelmente terá mais respostas de especialistas no Security StackExchange.


3
Concordo totalmente com isso. Para uma abordagem do lado do cliente funcionar, também seria necessário enviar o sal para o cliente, o que invalidaria todo o objetivo da salga!
James Wright

@ JamesWright: O objetivo é enviar um sal aleatório para cada uso, o que impede a reutilização ilegal de mensagens de login. (Uma forma de ataques de repetição). Enviar o mesmo sal toda vez é realmente inútil.
MSalters

O que você precisa fazer é usar um "nonce" ( en.wikipedia.org/wiki/Cryptographic_nonce ). Dessa forma, o servidor também controla o sal e o torna seguro. Hashing no lado do cliente também é importante para que o código JS injetado não possa encontrá-lo facilmente mais tarde. Mais aqui: stackoverflow.com/a/21716654/43615
Thomas Tempelmann

Para usar sal + nonce em um processo de autenticação de login, consulte esta resposta: stackoverflow.com/a/24978909/43615
Thomas Tempelmann

Obviamente, se você fizer o hash no lado do cliente, precisará usá-lo novamente no lado do servidor para evitar o argumento que está fazendo. Como outros apontam, porém, para a privacidade, você deseja uma criptografia do lado do cliente.
Daniel Methner 28/02

5

Observe que manter as senhas seguras contra terceiros não é tudo o que existe.

Assim que a privacidade estiver envolvida (e sempre que não estiver, hoje em dia?), Você não deseja saber a senha. Você não pode abusar ou vazar o que não possui , para que você e seus clientes possam dormir melhor se você nunca vir as senhas em texto não criptografado.

Portanto, fazer hash / criptografar no lado do cliente faz sentido.


Acordado! Muitas pessoas perdem esse ponto. Se eu fizer o download do seu banco de dados de senhas com hash salgado e eu puder quebrar apenas uma usando um banco de dados de pesquisa de hash, é provável que eu possa decifrá-las todas. Depois de ter 50 mil senhas originais, agora tenho a chave para xusuários em nserviços que criptografam apenas no servidor. Se cada serviço faz hash exclusivo da senha antes de deixar o cliente, o grande banco de dados de senhas entre serviços fica muito, muito menor. Verifique o tráfego de login da AWS e veja o que eles fazem. É provável, meu querido Watson.
F1lt3r


1

Eu tenho trabalhado muito nisso recentemente, IRL, há dois problemas com a criptografia hash / simétrica do lado do cliente que realmente matam a idéia: 1. Você precisa levar o sal de volta ao servidor ALGUM MOMENTO ... e criptografar no lado do cliente, você precisará de uma senha ... que derrote o objetivo. 2. Você expõe sua implementação de hash (não é um negócio ENORME, já que a maioria dos sites usa um de 3 ou 4 algos de hash), o que facilita o ataque (basta tentar um em vez de n).

O que acabei escolhendo foi criptografia assimétrica no cliente usando OpenPGP.js ou similar ... Isso depende de uma chave importada ou gerada no lado do cliente no cliente e no servidor que está enviando sua chave pública. Somente a chave pública do cliente pode ser enviada de volta ao servidor. Isso protege contra ataques MIM e é tão seguro quanto o dispositivo (atualmente eu armazeno a chave privada do cliente por padrão no localStore, é uma demonstração).

A principal vantagem disso é que eu nunca preciso ter dados de usuários armazenados / mesmo na memória não criptografada no meu servidor / repositório de dados (e a chave privada do meu servidor é fisicamente separada)

A base disso foi fornecer às pessoas uma maneira de se comunicar com segurança onde o HTTPS era restrito (por exemplo, Irã / Coréia do Norte atc ...) e também apenas um experimento divertido.

Estou MUITO longe dos primeiros a pensar nisso, http://www.mailvelope.com/ usa esse


1

Se alguém puder ver os dados entrando e saindo na sua conexão, a autenticação não o salvará. Em vez disso, eu faria o seguinte para coisas super secretas.

As senhas pré-divididas no lado do cliente antes de enviadas para o servidor. (O servidor armazena outro valor com hash e salgado desse hash enviado do navegador).

Portanto, um ataque intermediário poderia permitir que eles enviassem o mesmo valor de hash para o login que eles, mas a senha do usuário não seria conhecida. Isso os impediria de tentar outros serviços com as mesmas credenciais para efetuar login em outro lugar.

Os dados dos usuários também são criptografados no lado do navegador.

Ah, então um ataque intermediário obteria os dados criptografados, mas não seria capaz de descriptografá-los sem a senha real usada para efetuar o login. (senha de usuário armazenada no DOM no navegador quando eles efetuaram login). Assim, o usuário real veria o conteúdo descriptografado, mas o intermediário não. Isso também significa que qualquer NSA ou outra agência não poderá solicitar que você / empresa / provedor de hospedagem descriptografe esses dados, pois seria impossível que eles também o fizessem.

Alguns pequenos exemplos de ambos os métodos estão no meu blog http://glynrob.com/javascript/client-side-hashing-and-encryption/


1

Recentemente, o GitHub e o Twitter anunciaram que as senhas eram armazenadas em logs internos. Isso aconteceu inadvertidamente em relatórios de bugs e outros logs que chegaram ao splunk etc. No twitter, se a senha de Trump estava lá, pode ser um grande problema para um administrador "ver", pois outros sites provavelmente não são tão importantes. grande coisa, já que os administradores não teriam muita utilidade para isso. Independentemente de administradores, não gostamos de ver as senhas.

Portanto, a questão é realmente se o hash deve ocorrer no lado do cliente por segurança, mas como podemos proteger a senha antes que ela seja hash e comparada pelo servidor para que não seja registrada de alguma forma.

Criptografia não é uma má idéia, porque os desenvolvedores têm que passar por alguns obstáculos, e se você achar que as senhas entraram nos logs, poderá alterar a chave de criptografia, destruir o original e esses dados se tornarão inúteis. Melhor ainda, gire as chaves todas as noites e isso poderá reduzir bastante as janelas.

Você também pode fazer um hash no seu registro de usuário. As senhas vazadas seriam hash de texto simples. O servidor armazenaria uma versão em hash do hash. Claro que o hash se torna a senha, mas, a menos que você tenha uma memória fotográfica, não se lembrará de um código de 60 caracteres. Sal com o nome de usuário. Se você puder reunir algo sobre o usuário durante o processo de login (sem expor que o registro do usuário existe), poderá saltar com isso, criando um hash mais robusto que não pode ser compartilhado entre sites. Nenhum homem no meio seria capaz de cortar e colar o hash capturado entre os sites.

Combine com um cookie que não é enviado de volta ao servidor e você pode estar interessado em algo. Na primeira solicitação, envie um cookie ao cliente com uma chave e, em seguida, verifique se o cookie não retorna ao serviço de login, com poucas chances de ele ser registrado. Armazene a chave em um armazenamento de sessão e exclua-a logo após o logon ou quando a sessão expirar ... isso exige um estado para vocês do JWT, mas talvez apenas use um serviço nosql para isso.

Então, no caminho, um administrador encontra uma dessas senhas com hash e criptografadas no splunk ou em uma ferramenta de relatório de erros. Deve ser inútil para eles, pois eles não conseguem mais encontrar a chave de criptografia e, mesmo que o tenham, precisam fazer força bruta com um hash. Além disso, o usuário final não enviou nada em texto simples ao longo da linha, para que qualquer pessoa no meio tenha mais dificuldade e você não pode simplesmente acessar outro site e fazer login.


Exatamente minha preocupação. Se o servidor de alguma forma registrar acidentalmente devido a má implementação ou intenção maliciosa, é possível que outra conta do usuário possa ser comprometida se eles reutilizarem senhas.
Dan

0

Considere isto:-

O cliente envia uma solicitação ao servidor "Eu tenho uma senha para validar".

O servidor envia ao cliente uma sequência aleatória única e única. R$

O cliente incorpora a senha do usuário nesta string (com base em qualquer regra (variável) que você deseja aplicar).

O cliente envia a sequência para o servidor e, se a senha estiver OK, o servidor efetua login no usuário.

Se o servidor receber outra solicitação de login usando R $, o usuário será desconectado e a conta será congelada, pendente de investigação.

Obviamente, todas as outras precauções de segurança (normais) seriam tomadas.


0

Essa idéia do hash do lado do cliente é proteger o usuário, não o site. Como já mencionado muitas vezes, o texto sem formatação ou as senhas hash têm acesso ao seu site igualmente. Você não recebe um benefício de segurança.

Porém, a senha de texto real e simples dos usuários deve ser conhecida apenas por eles. Saber o que eles escolheram como senha é uma informação que pode ser usada contra eles em outros sites e sistemas. Você está sendo um site focado no cliente, protegendo-o de que a opção de senha seja descoberta pelos desenvolvedores do servidor ou por terceiros.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.