Os detalhes atuais sobre o sistema de armazenamento de senhas do Discourse podem ser encontrados em discourse/docs/SECURITY.md at main · discourse/discourse · GitHub. No momento da escrita deste texto, utilizamos PBKDF2-SHA256 com 600.000 iterações.
Em algumas situações, você pode querer exportar todas as senhas hash do Discourse e importá-las para outro sistema. Por exemplo, você pode estar migrando da autenticação nativa do Discourse para um sistema SSO personalizado. Lembre-se: é impossível extrair as senhas originais do banco de dados, portanto, seu sistema de destino precisa ser capaz de executar o mesmo algoritmo de hash com os mesmos parâmetros.
Os dados de senha são armazenados na tabela user_passwords, que contém as colunas password_hash, password_salt e password_algorithm. A coluna password_algorithm armazena o prefixo completo do algoritmo PHC (por exemplo, $pbkdf2-sha256$i=600000,l=32$), que pode variar por usuário se a contagem de iterações tiver sido aumentada ao longo do tempo.
Você pode usar o Data Explorer para exportar as informações em um formato legível por computador:
SELECT users.id, users.username, up.password_salt, up.password_hash, up.password_algorithm
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
WHERE users.id > 0
Isso exportará os dados no formato nativo do Discourse. O salt está codificado em hexadecimal e o hash da senha também está codificado em hexadecimal.
Alguns sistemas externos suportam o formato de string PHC, que visa representar a saída de uma função de hash de senha de forma independente do algoritmo. Para o pbkdf2-sha256, essa string contém o tipo de algoritmo, o número de iterações, o salt codificado em base64 e o hash codificado em base64. Felizmente, o Postgres pode lidar com tudo isso para nós em uma única consulta.
Para gerar strings PHC para cada usuário do Discourse, você pode usar uma consulta no Data Explorer como esta:
SELECT users.id, users.username,
concat(
up.password_algorithm,
replace(encode(up.password_salt::bytea, 'base64'), '=', ''),
'$',
replace(encode(decode(up.password_hash, 'hex'), 'base64'), '=', '')
) as phc
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
WHERE users.id > 0
Se você usa o Auth0, então use esta consulta em vez da anterior:
SELECT
user_emails.email,
users.active as email_verified,
concat(
up.password_algorithm,
replace(encode(up.password_salt::bytea, 'base64'), '=', ''),
'$',
replace(encode(decode(up.password_hash, 'hex'), 'base64'), '=', '')
) as password_hash
FROM users
INNER JOIN user_passwords up ON users.id = up.user_id
INNER JOIN user_emails
ON users.id = user_emails.user_id
AND user_emails.primary IS TRUE
AND users.id > 0
