Você mantém um aplicativo existente com uma base de usuários estabelecida. Com o tempo, é decidido que a técnica atual de hash de senha está desatualizada e precisa ser atualizada. Além disso, por motivos de UX, você não deseja que os usuários existentes sejam forçados a atualizar suas senhas. Toda a atualização do hash da senha precisa ocorrer atrás da tela.
Suponha um modelo de banco de dados 'simplista' para usuários que contenha:
- identidade
- O email
- Senha
Como se pode resolver esse requisito?
Meus pensamentos atuais são:
- crie um novo método de hash na classe apropriada
- atualize a tabela do usuário no banco de dados para conter um campo de senha adicional
- Depois que um usuário efetuar login com êxito usando o hash de senha desatualizado, preencha o segundo campo de senha com o hash atualizado
Isso me deixa com o problema de que não posso diferenciar razoavelmente entre usuários que possuem e aqueles que não atualizaram seu hash de senha e, portanto, serão forçados a verificar os dois. Isso parece terrivelmente falho.
Além disso, isso significa basicamente que a antiga técnica de hash pode ser forçada a permanecer indefinidamente até que cada usuário atualize sua senha. Somente naquele momento eu poderia começar a remover a verificação de hash antiga e remover o campo supérfluo do banco de dados.
Estou procurando principalmente algumas dicas de design aqui, já que minha 'solução' atual está suja, incompleta e não, mas se for necessário um código real para descrever uma possível solução, fique à vontade para usar qualquer idioma.
fonte
Respostas:
Eu sugeriria adicionar um novo campo, "hash_method", com talvez 1 para indicar o método antigo e 2 para indicar o novo método.
Razoavelmente falando, se você se importa com esse tipo de coisa e seu aplicativo é relativamente longo (o que aparentemente já é), isso provavelmente acontecerá novamente, pois a criptografia e a segurança da informação são um campo tão evolutivo e imprevisível. Houve um tempo em que uma simples execução no MD5 era padrão, se o hash era usado! Então, pode-se pensar que eles devem usar SHA1, e agora há salga, sal global + sal aleatório individual, SHA3, diferentes métodos de geração de números aleatórios prontos para criptografia ... isso não vai apenas 'parar', então você pode conserte isso de maneira extensível e repetível.
Então, digamos que agora você tenha algo como (em pseudo-javascript por simplicidade, espero):
Agora, percebendo que existe um método melhor, você só precisa fazer uma pequena refatoração:
Nenhum agente secreto ou programador foi prejudicado na produção dessa resposta.
fonte
newHash(oldHash, salt)
ounewHash(password, salt)
Se você se importa o suficiente com a implementação do novo esquema de hash para todos os usuários o mais rápido possível (por exemplo, porque o antigo é realmente inseguro), existe realmente uma maneira de "migração" instantânea de cada senha.
A idéia é basicamente hash do hash . Em vez de aguardar que os usuários forneçam suas senhas existentes (
p
) no próximo login, use imediatamente o novo algoritmo de hash (H2
) no hash existente já produzido pelo antigo algoritmo (H1
):Depois de fazer essa conversão, você ainda poderá executar a verificação de senha. você só precisa calcular em
H2(H1(p'))
vez do anteriorH1(p')
sempre que o usuário tentar fazer login com senhap'
.Em teoria, esta técnica poderia ser aplicada a múltiplos migrações (
H3
,H4
, etc.). Na prática, você desejaria se livrar da antiga função hash, por motivos de desempenho e legibilidade. Felizmente, isso é bastante fácil: no próximo login bem-sucedido, simplesmente calcule o novo hash da senha do usuário e substitua o hash-a-a-hash existente por ele:Você também precisará de uma coluna adicional para lembrar o hash que está armazenando: aquele da senha ou do hash antigo. No infeliz evento de vazamento do banco de dados, essa coluna não deve facilitar o trabalho do cracker; independentemente do seu valor, o invasor ainda teria que reverter o
H2
algoritmo seguro em vez do antigoH1
.fonte
Sua solução (coluna adicional no banco de dados) é perfeitamente aceitável. O único problema com ele é o que você já mencionou: que o hash antigo ainda é usado por usuários que não se autenticaram desde a alteração.
Para evitar essa situação, você pode esperar que os usuários mais ativos alternem para o novo algoritmo de hash e:
Remova as contas de usuários que não se autenticam por muito tempo. Não há nada errado em remover uma conta de usuário que nunca acessa o site há três anos.
Envie um email para os demais usuários entre aqueles que não se autenticaram por um tempo, informando que podem estar interessados em algo novo. Isso ajudará a reduzir ainda mais o número de contas que usam o hash mais antigo.
Cuidado: se você tem uma opção sem spam, os usuários podem verificar no seu site, não envie o email aos usuários que o verificaram.
Por fim, algumas semanas após a etapa 2, destrua a senha dos usuários que ainda estão usando a técnica antiga. Quando e se tentarem se autenticar, verão que a senha é inválida; se eles ainda estiverem interessados no seu serviço, poderão redefini-lo.
fonte
Você provavelmente nunca terá mais do que alguns tipos de hash, para poder resolver isso sem estender seu banco de dados.
Se os métodos tiverem comprimentos diferentes de hash e o comprimento de cada método for constante (por exemplo, a transição de md5 para hmac-sha1), você poderá diferenciar o método do comprimento de hash. Se eles tiverem o mesmo comprimento, você poderá calcular o hash usando o novo método primeiro, depois o método antigo se o primeiro teste falhar. Se você possui um campo (não mostrado) informando quando o usuário foi atualizado / criado pela última vez, você pode usá-lo como um indicador para qual método usar.
fonte
Eu fiz algo assim e existe uma maneira de saber se é o novo hash E torná-lo ainda mais seguro. Acho que mais seguro é uma coisa boa para você, se você estiver investindo um tempo para atualizar seu hash ;-)
Adicione uma nova coluna à sua tabela de banco de dados chamada "salt" e use-a como um sal gerado aleatoriamente por usuário. (praticamente evita ataques à mesa arco-íris)
Dessa forma, se minha senha for "pass123" e o salt aleatório for 3333, minha nova senha será o hash de "pass1233333".
Se o usuário tem sal, você sabe que é o novo hash. Se o sal do usuário for nulo, você sabe que é o hash antigo.
fonte
Não importa quão boa seja sua estratégia de migração, se o banco de dados já tiver sido roubado (e você não puder provar negativamente que isso nunca aconteceu), as senhas armazenadas com funções de hash inseguras já poderão ser comprometidas. A única redução para isso é exigir que os usuários alterem suas senhas.
Este não é um problema que pode ser resolvido (apenas) escrevendo código. A solução é informar usuários e clientes sobre os riscos aos quais foram expostos. Quando você estiver disposto a se abrir, pode fazer a migração simplesmente redefinindo a senha de todos os usuários, porque é a solução mais fácil e segura. Todas as alternativas são realmente sobre esconder o fato de que você errou.
fonte