Esporta gli hash delle password nel formato PHC

I dettagli attuali sul sistema di archiviazione delle password di Discourse sono disponibili all’indirizzo discourse/docs/SECURITY.md at main · discourse/discourse · GitHub. Al momento della stesura, utilizziamo PBKDF2-SHA256 con 600.000 iterazioni.

In alcune situazioni, potresti voler esportare tutte le password crittografate da Discourse e importarle in un altro sistema. Ad esempio, potresti essere in fase di migrazione dall’autenticazione integrata di Discourse a un sistema SSO personalizzato. Ricorda che è impossibile estrarre le password originali dal database, quindi il sistema di destinazione deve essere in grado di eseguire lo stesso algoritmo di hashing con gli stessi parametri.

I dati delle password sono archiviati nella tabella user_passwords, che contiene le colonne password_hash, password_salt e password_algorithm. La colonna password_algorithm memorizza l’intero prefisso dell’algoritmo PHC (ad esempio $pbkdf2-sha256$i=600000,l=32$), che può variare da utente a utente se il numero di iterazioni è stato aumentato nel tempo.

Puoi utilizzare Data Explorer per esportare le informazioni in un formato leggibile dal computer:

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

Questo esporterà i dati nel formato nativo di Discourse. Il salt è codificato in esadecimale e l’hash della password è anch’esso codificato in esadecimale.

Alcuni sistemi esterni supportano il formato stringa PHC, che mira a rappresentare l’output di una funzione di hashing delle password in modo indipendente dall’algoritmo. Per pbkdf2-sha256, questa stringa contiene il tipo di algoritmo, il numero di iterazioni, il salt codificato in base64 e l’hash codificato in base64. Fortunatamente, Postgres può gestire tutto questo per noi in una singola query.

Per generare stringhe PHC per ogni utente di Discourse, puoi utilizzare una query di Data Explorer come questa:

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 utilizzi Auth0, usa invece questa:

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
13 Mi Piace

Solo una nota: io (con un po’ di aiuto dal team cordiale di Auth0) ho finito per modificare la query di esempio per generare stringhe PHC valide per l’importazione delle password degli utenti in Auth0.

Ho anche codificato il sale in base64 modificando questa riga

salt,

in

replace(encode(users.salt::bytea, 'base64'), '=', ''),

Vedi oltre qui (incluso una guida passo passo su come importare gli utenti di Discourse e le loro password in Auth0).

1 Mi Piace

Grazie @angus - è interessante perché abbiamo avuto un cliente che ha utilizzato la query nell’OP per importare con successo gli utenti in Auth0. Mi chiedo se qualcosa sia cambiato nel loro processo di importazione - per quanto mi ricordi, la possibilità di importare stringhe PHC in Auth0 era molto recente lo scorso novembre :thinking:

3 Mi Piace

Sì, me lo chiedevo anch’io e la pensavo allo stesso modo.

Non ero nemmeno molto sicuro del linguaggio usato nella specifica PHC. Non sono sicuro che significhi che il sale debba essere codificato in B64 o meno.

Il sale consiste in una sequenza di caratteri in: [a-zA-Z0-9/+.-] (lettere minuscole, lettere maiuscole, cifre, /, +, . e -). La specifica della funzione DEVE definire l’insieme dei valori di sale validi e una lunghezza massima per questo campo. Le funzioni che operano su sali binari arbitrari DOVREBBERO definire tale campo come la codifica B64 di un valore binario la cui lunghezza rientra in un intervallo o in un insieme di intervalli definiti.

2 Mi Piace

Scusa se mi sono discostato dall’argomento, ma qualcuno ha importato gli hash delle password da Auth0 a Discourse? Sto pensando di effettuare questa migrazione, quindi qualsiasi aiuto sarebbe apprezzato. Non sono un cliente a pagamento di Auth0, quindi volevo solo sapere se è fattibile prima di pagare per l’esportazione degli hash delle password.

Grazie.

L’importazione delle password non è supportata dal nucleo di Discourse, sebbene potrebbe essere possibile utilizzando una versione adattata di questo plugin di terze parti:

4 Mi Piace

Grazie! Ho trovato il repository su GitHub, ma non l’argomento qui su meta.

1 Mi Piace

Ehi @angus, stiamo facendo un po’ di pulizia qui.

È vero che il blocco di codice dell’OP dovrebbe essere:

SELECT id, username,
  concat(
    '$pbkdf2-sha256$i=64000,l=32$',
    replace(encode(users.salt::bytea, 'base64'), '=', ''),
    '$',
    replace(encode(decode(password_hash, 'hex'), 'base64'), '=', '')
  ) as phc
FROM users

e includere qualcosa come:

Per ulteriori informazioni sull’importazione delle password di Discourse in Auth0, vedi Bulk User Import Custom Password Hash Issue - Auth0 Community.

Per spostare i dati da Auth0 a Discourse, questo potrebbe essere utile: Migrated password hashes support.

3 Mi Piace

Sì, sembra tutto a posto.

Forse vorresti aggiungere una nota sul fatto che ogni importazione richiede un’attenzione specifica, poiché i dati utente gestiti variano a seconda del caso d’uso, ovvero non limitarti a copiare e incollare queste query.

Inoltre, l’esportazione delle password in PHC non è necessariamente destinata solo ad Auth0, quindi forse è meglio riferirsi a ciò come a un “esempio”.

La query completa che ho utilizzato per la mia esportazione era

SELECT
    user_emails.email,
    users.active as email_verified,
    concat(
        '$pbkdf2-sha256$i=64000,l=32$',
        replace(encode(users.salt::bytea, 'base64'), '=', ''),
        '$',
        replace(encode(decode(users.password_hash, 'hex'), 'base64'), '=', '')
    ) as password_hash
FROM users
INNER JOIN user_emails 
ON users.id = user_emails.user_id 
AND user_emails.primary IS TRUE
AND users.id > 0
2 Mi Piace