Passwort-Hashes im PHC-Format exportieren

Aktuelle Details zum Passwort-Speichersystem von Discourse finden Sie unter discourse/docs/SECURITY.md at main · discourse/discourse · GitHub. Zum Zeitpunkt des Schreibens verwenden wir PBKDF2-SHA256 mit 600.000 Iterationen.

In einigen Fällen möchten Sie möglicherweise alle gehashten Passwörter aus Discourse exportieren und in ein anderes System importieren. Beispielsweise könnten Sie von der integrierten Discourse-Authentifizierung zu einem benutzerdefinierten SSO-System migrieren. Denken Sie daran, dass es unmöglich ist, die ursprünglichen Passwörter aus der Datenbank zu extrahieren. Daher muss Ihr Zielsystem in der Lage sein, denselben Hashing-Algorithmus mit denselben Parametern auszuführen.

Passwortdaten werden in der Tabelle user_passwords gespeichert, die die Spalten password_hash, password_salt und password_algorithm enthält. Die Spalte password_algorithm speichert das vollständige PHC-Algorithmus-Präfix (z. B. $pbkdf2-sha256$i=600000,l=32$), das je Benutzer variieren kann, wenn die Iterationsanzahl im Laufe der Zeit erhöht wurde.

Sie können den Data Explorer verwenden, um die Informationen in einem für Computer lesbaren Format zu exportieren:

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

Dies exportiert die Daten im nativen Discourse-Format. Der Salt ist hexadezimal kodiert, und der Passwort-Hash ist ebenfalls hexadezimal kodiert.

Einige externe Systeme unterstützen das PHC-String-Format, das eine algorithmusübergreifende Darstellung des Outputs einer Passwort-Hashing-Funktion ermöglicht. Für pbkdf2-sha256 enthält dieser String den Algorithmentyp, die Anzahl der Iterationen, den base64-kodierten Salt und den base64-kodierten Hash. Glücklicherweise kann Postgres dies alles für uns in einer einzigen Abfrage erledigen.

Um PHC-Strings für jeden Discourse-Benutzer zu generieren, können Sie eine Data-Explorer-Abfrage wie diese verwenden:

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

Wenn Sie Auth0 verwenden, benötigen Sie stattdessen Folgendes:

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 „Gefällt mir“

Nur ein kurzer Hinweis: Ich habe (mit etwas Hilfe vom freundlichen Auth0-Team) die Beispielabfrage angepasst, um gültige PHC-Strings für den Import von Benutzerpasswörtern in Auth0 zu generieren.

Außerdem habe ich den Salt als Base64 kodiert, indem ich diese Zeile

salt,

in

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

verändert habe.
Weitere Details finden Sie hier (inklusive einer Schritt-für-Schritt-Anleitung zum Import von Discourse-Benutzern und deren Passwörtern in Auth0).

1 „Gefällt mir“

Danke @angus – das ist interessant, denn wir hatten bereits einen Kunden, der die Abfrage aus dem OP verwendet hat, um Benutzer erfolgreich in Auth0 zu importieren. Ich frage mich, ob sich etwas in ihrem Importprozess geändert hat – soweit ich mich erinnere, war die Möglichkeit, PHC-Strings in Auth0 zu importieren, im November noch sehr neu :thinking:

3 „Gefällt mir“

Ja, ich habe mich auch darüber gewundert und war derselben Meinung.

Ich war mir auch nicht ganz sicher bezüglich der Formulierung in der PHC-Spezifikation. Nicht klar, ob dies bedeutet, dass der Salt B64-kodiert sein muss oder nicht.

Der Salt besteht aus einer Zeichenfolge aus: [a-zA-Z0-9/+.-] (Kleinbuchstaben, Großbuchstaben, Ziffern, /, +, . und -). Die Funktionsspezifikation MUSS die Menge gültiger Salt-Werte und eine maximale Länge für dieses Feld definieren. Funktionen, die mit beliebigen binären Salts arbeiten, SOLLTEN definieren, dass dieses Feld die B64-Kodierung eines binären Werts ist, dessen Länge in einem definierten Bereich oder einer Menge von Bereichen liegt.

2 „Gefällt mir“

Entschuldigung, dass ich vom Thema abschweife, aber hat jemand Passwort-Hashes von Auth0 nach Discourse importiert? Ich überlege, diese Migration durchzuführen, daher wäre jede Hilfe willkommen. Ich bin kein zahlender Auth0-Kunde, daher wollte ich nur wissen, ob dies machbar ist, bevor ich für den Export der Passwort-Hashes bezahle.

Danke.

Das Importieren von Passwörtern wird von Discourse Core nicht unterstützt, es könnte jedoch mit einer angepassten Version dieses Drittanbieter-Plugins möglich sein:

4 „Gefällt mir“

Vielen Dank! Ich habe das Repository auf GitHub gefunden, aber das Thema hier auf Meta nicht.

1 „Gefällt mir“

Hey @angus, wir räumen hier gerade auf.

Stimmt es, dass der Code-Block des OPs so lauten sollte:

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

und etwas wie Folgendes enthalten sollte:

Weitere Informationen zum Importieren von Discourse-Passwörtern in Auth0 finden Sie unter Bulk User Import Custom Password Hash Issue - Auth0 Community.

Um Daten von Auth0 nach Discourse zu übertragen, könnte dies hilfreich sein: Migrated password hashes support.

3 „Gefällt mir“

Ja, das sieht gut aus.

Vielleicht solltest du noch erwähnen, dass jeder Import besondere Aufmerksamkeit erfordert, da die zu verarbeitenden Benutzerdaten je nach Anwendungsfall variieren – kopiere diese Abfragen also nicht einfach blindlings.

Außerdem dient das Exportieren von Passwörtern in PHC nicht ausschließlich für Auth0. Vielleicht sollte das daher nur als „Beispiel

2 „Gefällt mir“