Hashing de Senhas no MariaDB 4.1
As contas de usuários do MariaDB estão lisatadas na tabela user
do banco de dados MariaDB
. Para cada conta do MariaDB é definida uma senha, no entanto o que está armazenado na coluna Password
da tabela user
não seja uma versão da senha em texto puro, mas um valor hash computado para ela. Valores hash de senha são calculados pela função PASSWORD()
.
O MariaDB usa senhas em duas fases da comunicação cliente/servidor:
- Primeiro, quando um cliente tenta se conectar ao servidor, existe uma etapa de autenticação inicial na qual o cliente deve apresentar uma senha que combina com o valor hash armazenado na tabela de usuários para a conta que aquele cliente deseja usar.
- Em segundo lugar, depois que o cliente conecta, ele pode configurar ou alterar o hash da senha para as contas listadas na tabela de usuário (se ele tiver privilégios suficientes).O cliente pode fazer isto usando a função PASSWORD() para gerar uma hash da senha ou usando as instruções GRANT ou SET PASSWORD.
Em outra palavras, o servidor usa valores hash durante a autenticação quando um cliente tenta a primeira conexão. O servidor gera os valores hash se um cliente conectado chama a função PASSWORD()
ou usa uma instrução GRANT
ou SET PASSWORD
para definir ou alterar uma senha.
O mecanismo de hash da senha foi atualizado no MariaDB para fornecer melhor segurança e reduzir os riscos de senhas serem roubadas. No entanto, Este novo mecanismo só é interpretado pelo servidor 4.1 e clientes 4.1, que podem resultar em alguns problemas de compatibilidade. Um cliente 4.1 pode conectar a um servidor pre-4.1, porque o cliente entende tanto o antigo quanto o novo mecanismo hash de senha. No entanto, um cliente pre-4.1 que tentar se conectar a um servidor 4.1 pode encontrar dificuldades. Por exemplo, um cliente MariaDB
4.0 que tentar se conectar a um servidor 4.1 pode falhar com a seguinte mensagem de erro:
shell> MariaDB
Client does not support authentication protocol requested by server; consider upgrading MariaDB client
A seguinte discussão descreve a diferença entre o antigo e o novo mecanismo de senha, e o que você deve fazer se você atualizar o seu servidor para a versão 4.1 mas precizar de manter compatibilidade com clientes pre-4.1.
Nota: Esta discussão contrasta no comportamento da versão 4.1 com o comportamento da pre-4.1, mas o da versão 4.1 descrito aqui começa relamente na versão 4.1.1. O MariaDB é uma distribuição disferente
porque ela tem um mecanismo um pouco diferente daquele implementado na 4.1.1 e acima. Diferenças entre a versão 4.1.0 e as versões mais recentes são descritas posteriormente.
Antes do MariaDB, o hash de senha calculado pela função PASSWORD()
tem tamanho de 16 bytes. Este hash se parece com:
mysql> SELECT PASSWORD('mypass');
+--------------------+
| PASSWORD('mypass') |
+--------------------+
| 6f8c114b58f2ce9e |
+--------------------+
A coluna Password
da tabela user
(na qual estes hashes são armazenados) também têm 16 bytes de tamanho antes do MariaDB 4.1.
A partir do MariaDB, a função PASSWORD()
foi modificada para produzir um valor hash de 41 bytes.
mysql> SELECT PASSWORD('mypass');
+-----------------------------------------------+
| PASSWORD('mypass') |
+-----------------------------------------------+
| *43c8aa34cdc98eddd3de1fe9a9c2c2a9f92bb2098d75 |
+-----------------------------------------------+
De acordo com o mostrado, a coluna Password
na tabela user
também deve ter 41 bytes para armazeanar estes valores.
- Se você realiza uma nova instalação do MariaDB, a coluna
Password
será convertida para o tamanho de 41 bytes automaticamente. - Se você atualizar uma instalação mais antiga para a versão 4.1, você executar o script
mysql_fix_privilege_tables
para atualizar o tamanho da colunaPassword
de 16 para 41 bytes. (O script não altera valores de senhas existentes, que continuam com 16 bytes.)
Uma coluna Password
mais larga pode armazenar hashes de senha no formato novo e no antigo. O formato de qualquer valor de hash de senha dado podeser determinado de dois modos:
- A diferença óbvia é o tamanho (16 bytes versus 41 bytes)
- A segunda diferença é que os hashes de senha no novo formato sempre começam com um caracter '
*
', que as senhas no formato antigo nunca faziam.
O formato maior do hash de senha tetm melhores propriedades criptográficas, e a autenticação do cliente baseada em hashs mais longos é mais segura que aquela baseada nos antigos hashes menores.
A diferença entre os hashs de senhas menores e maiores são relevantes em como o servidor usa as senhas durante a autenticação e como ela gera hash de senhas para clientes conectados que realizam operações de alteração de senha.
O modo no qual o servidor usa o hash de senha durante a autenticação é afetada pela largura da coluna Password:
- Se a coluna não for larga, apenas a autenticação de hash curto é usada.
- Se a coluna é larga, ela pode guardar tanto hash curtas quanto hashs longas, e o servidor pode usar ambos os formatos:
- Clientes pre-4.1 podem conectar, mas como els só conhecem o mecanismo hash antigo, eles só podem se conectar pelas contas com hashes curtos.
- Clientes 4.1 podem autenticar contas com hashes longos ou curtos.
Para contas com o hash curto, o processo de autenticação é na verdade um pouco mais seguro para clientes 4.1 que para clientes mais antigos. Em termos de segurança, o gradiente do menos para o mais seguro é:
- Clientes pre-4.1 autenticando em contas com hash de senha curto
- Clientes 4.1 autenticando em contas com hash de senha curto
- Clientes 4.1 autenticando em contas com hash de senha longo
O modo no qual o servidor gera hashes de senhas para clientes conectados é afetado pela largura da coluna Password
e pela opção --old-passwords
. Um servidor 4.1 gera hashes longos apenas se certas condicões forem encontradas: A coluna Password
deve ser grande o suficiente para armazenar valores longos e a opção --old-passwords
não deve ser dada. Estas condições se aplicam da seguinte forma:
- A coluna
Password
deve ser grande o suficiente para armazenar hashes longos (41 bytes). Se a coluna não foi atualizada e ainda tem a largura de 16 bytes (antes da 4.1), o servidor avisa que o hash não pode caber nela e gera apenas hashes curtos quando um cliente realiza a operação de troca de senha usandoPASSWORD()
,GRANT
, ouSET PASSWORD
. (Este comportamento ocoree se você tiver atualizado para a versão 4.1 mas não executou o scriptmysql_fix_privilege_tables
para aumentar a colunaPassword
.) - Se a coluna
Password
for larga, ela poderá aramazenar tanto os hashes de senha curtos quanto os longos. Neste caso,PASSWORD()
,GRANT
, eSET PASSWORD
irão gerar hashes longos a menos que o servidor tenha sido iniciado com a opção--old-passwords
. Esta opção força o servidor a gerar hashes de senha curtos.
O propósito da opção --old-passwords
é permitir que você mantenha compatibilidade com clientes com versões anteriores à 4.1 sob circunstâncias nas quais os servidores gerariam hashes de senha longos. Ele não afeta a autenticação (clientes 4.1 podem ainda usar contas que possuem hash de senha longo), mas ele não previne a criaçõa de um hash de senha longo na tabela user
como resultado de uma operação de troca de senha. Onde isto ocorrer, a conta não mais poderá ser usada por clientes pré-4.1. Se a opção --old-passwords
, o seguinte cenário é possível:
- Um cliente antigo conecta a uma conta que têm um hash de senha curto.
- O cliente altera a senha das contas. Sem
--old-passwords
, isto resulta na conta que têm um hash de senha longo. - A próxima vez que o cliente antigo tentar se conectar à conta, ele não conseguirá, porque a conta agora exige o novo mecanismo de hash durante a autenticação. (Uma vez que uma conta tem um hash de senha longo na tabela de usuário, apenas os clientes 4.1 poderão ser autenticados, porque clientes de versões anteriores a 4.1 não entendem o hash longo.)
Este cenário mostra que é perigoso executar um servidor 4.1 sem usar a opção --old-passwords
, operações de alteração de senha não irão gerar hashes de senha longos e assim não faz com que as contas se tornem inacessíveis para clientes mais antigos. (Estes clientes não podem bloquear eles mesmos inadivertidamente alterando suas senhas e ficando com um hash de senha longo.
A desvantagem da opção --old-passwords
é que qualquer senha que você criar ou alterar usará hashes curtos, mesmo para clientes 4.1. Assim, você perde a segurança adicional fornecida pelos hashes de senha longos. Se você quiser criar uma conta qye tenha um hash longo (por exemplom parr uso pelos clientes 4.1), você deve fazê-lo enquanto executa o servidor sem a opção --old-passwords
.
Os seguintes cenários são possíveis para executar um servidor 4.1:
Cenario 1) Coluna Password
menor na tabela de usuários
- Apenas hashes curtos podem ser armazenados na coluna
Password
. - O servidor usa apenas hasghes curtos durante a autenticação do cliente.
- Para clientes conectados, operações de geração de hash de senha envolvendo
PASSWORD()
,GRANT
ouSET PASSWORD
usa hashes curtos exclusivamebnte. Qualquer alteração a senha de uma conta faz com que a conta tenha um hash de senha curto. - A opção
--old-passwords
pode ser usada mas é superflua porque com uma colunaPassword
menor, o servidor irá gerar hashes de senha curtos de qualquer forma.
Cenário 2) Colunas Password
longas; servidor não iniciado com a opção --old-passwords
- Hashes de senha longos e curtos podem ser armazenados na coluna
Password
. - Clientes 4.1 podem autenticar contas com hashes curtos ou longos.
- Clientes anteioriores ao 4.1 só podem autenticar contas com hash curto.
- Para clientes conectados, operações de geração de hash de senha envolvendo
PASSWORD()
,GRANT
, ouSET PASSWORD
usam hashes longos exclusivamente. Qualquer mudança na senha de uma conta fará com que ela possua um hash de senha longo. OLD_PASSWORD()
pode ser usado para gerar explicitamente um hash curto. Por exemplo, para atribuir uma senha curta a uma conta, useUPDATE
da seguinte forma:mysql>
UPDATE user SET Password = OLD_PASSWORD('mypass')
->WHERE Host = 'some_host' AND User = 'some_user';
mysql>FLUSH PRIVILEGES;
Como indicado anteriormente, o perigoso neste cenário é que é possível que contas com hashes de senha curtos se tornem inacessíveis para cliente anteriores ao 4.1. Qualquer alteração a senha de uma conta feita via GRANT
, SET PASSWORD
, ou PASSWORD()
faz com que a conta tenha um hash de senha longo, e a partir deste ponto, nenhum cliente anterior ao 4.1 poderá autenticar esta conta até que ele seja atualizado para a versão 4.1.
Cenário 3) Coluna Password
longa; servidor iniciado com a opção --old-passwords
- Hashes longos e curtos podem ser armazenados na coluna
Password
. - Clientes 4.1 podem autenticar contas que tenham hashes longos ou curtos (mas note que é possível criar hashes longos apenas quando o servidor é iniciado sem
--old-passwords
). - Clientes anteriores ao 4.1 podem autentticar apenas contas com hashes curtos.
- Para clientes conectados, operações de geração de hash de senha envolvendo
PASSWORD()
,GRANT
, ouSET PASSWORD
usa hashes curtos exclusivamente. Qualquer alteração em uma senha de conta faz com que a conta tenha um hash de senha curto.
Neste cenário, você não pode criar contas que tenham hashes de senha longo, porque --old-passwords
previne a criação de hashes longos. Também, se você criar uma conta com um hash longo antes de usar a opção --old-passwords
, alterar a senha da conta enquanto --old-passwords
está funcionando faz com que seja dada a conta uma sena curta, fazendo com que ela perca os benefícios de segurança de um hash longo.
As disvantagens para este cenário pode ser resumido como a seguir:
Cenário 1) Você não pode tirar vantagem do hash longo que fornece mais autenticação segura.
Cenário 2) Contas com hashes curtos tornam clientes anteriores ao 4.1 inacessíveis se você alterar a senha deles sem usar OLD_PASSWORD()
explicitamente.
Cenário 3) --old-passwords
evita que as contas com hashes curtos se tornem inacessíveis, mas operações de alteração de senhas fazem com que as contas com hashes longos seja revertida para hashes curtos, e você não pode alterá-las de volta para hashes longos enquanto --old-passwords
está em efeito.
Implicações de Alteração de Hashes de Senha para Aplicativos
Um atualização para o MariaDB para trazer problemas de compatibilidade para aplicações que usam PASSWORD()
para gerar senha para os seus próprios propósitos. (Aplicativos não devem fazer isto, porque PASSWORD()
deve ser usado paenas para gerenciar contas do MariaDB. Mas algumas aplicações usam PASSWORD()
para seus próprios propósitos.) Se você atualizar para o MariaDB e executar o servidor sob condições onde ele gera hashes de senha longo, uma aplicação que usa PASSWORD()
para as suas próprias senhas irá falhar. O curso de ação recomendado é modificar o aplicativo para usar outras funções como SHA1()
ou MD5()
para produzir valores de hash. Se isto não for possível você pode utilizar a função OLD_PASSWORD()
, que é fornecida para gerar hashes curtos no formato antigo. (Mas note que OLD_PASSWORD()
pode vir a não ser mais suportado.)
Se o servidor está rodando sob circuntâncias onde ele gera hashes de senha curtos, OLD_PASSWORD()
está disponível mas é equivalente a PASSWORD()
.
Hash de senhas no MariaDB 4.1.0 difere do hash no 4.1.1 e acima. As diferenças da versão 4.1.0 são as seguintes:
- Hashes de senhas de 45 bytes em vez de 41 bytes.
- A função
PASSWORD()
não é repetitível. Isto é, com um dado argumentoX
, successivas chamadas aPASSWORD(X)
geram diferentes resultados.