Verwendung von Discourse als Account-Anbieter und PBKDF2-Probleme

Hallo. Das ist wahrscheinlich eine dumme Frage, aber wir migrieren unser Forum von XenForo zu Discourse. Wir haben einen Backend-Server für die Autorisierung, der sich mit der Datenbank verbindet und Anmeldeinformationen gegen die Benutzertabelle prüft.

XenForos bcrypt-Algorithmus funktionierte wie erwartet und ohne Probleme. Als wir jedoch zu Discourse migrierten, schien der PBKDF2-Algorithmus nicht meinen Erwartungen zu entsprechen. Genau dasselbe Passwort, genau dieselbe Salt, genau dieselbe Anzahl von Iterationen und Länge, aber der Ausgabe-Hash ist anders.

Ich habe verschiedene Implementierungen des PBKDF2-Algorithmus ausprobiert, aber alle geben denselben (von Discourse abweichenden) Hash aus. Einschließlich meiner eigenen Implementierung.
Ich würde Mechanismen wie OAuth2 oder SSO wegen des zusätzlichen Overheads und des zusätzlichen Aufwands, den sie uns auferlegen, lieber vermeiden.

Hat jemand Discourse für solche Anwendungsfälle verwendet und, wenn ja, wie haben Sie dieses Problem gelöst?

Verwenden Sie das Migrate Password Plugin?

Nein, zumindest nicht, soweit ich weiß. Sprechen Sie über dies?

1 „Gefällt mir“

Haben Sie die Implementierung von openssl ausprobiert? Das ist es, was wir verwenden (Sie können es in discourse/lib/pbkdf2.rb sehen).

Als Beispiel, nachdem das Passwort eines Benutzers auf swordfish# gesetzt wurde:

discourse_development=# select password_hash, salt, password_algorithm from users where id=2;
-[ RECORD 1 ]------+-----------------------------------------------------------------
password_hash      | 67650523776bdc87ebcd2fc11719553c87b11e6c4da49806d9d5232460d2adc9
salt               | 712ef44dd6fe6d6f0f1b6f702bb78459
password_algorithm | $pbkdf2-sha256$i=600000,l=32$
$ openssl kdf \
  -kdfopt pass:'swordfish#' \
  -kdfopt salt:712ef44dd6fe6d6f0f1b6f702bb78459  \
  -kdfopt digest:SHA2-256 \
  -kdfopt iter:600000 \
  -keylen 32 \
  PBKDF2 \
  | tr -d : | tr '[:upper:]' '[:lower:]'
67650523776bdc87ebcd2fc11719553c87b11e6c4da49806d9d5232460d2adc9
1 „Gefällt mir“

Wir haben hauptsächlich die Implementierung von Go’s crypto/bcrypt für Xenforo verwendet. Die gleichen Hashes aus verschiedenen pbkdf2-Algorithmus-Implementierungen lassen mich vermuten, dass Go möglicherweise Strings auf eine etwas andere Weise speichert oder in Bytes umwandelt.

Das muss ich morgen ausprobieren (es ist spät hier). Wenn OpenSSL mir das gewünschte Ergebnis liefert, müsste ich nach OpenSSL-Bindings für Go suchen oder zu einer völlig anderen Sprache (die OpenSSL-Bindings hat) für das Backend wechseln.

Haben Sie ein kurzes Testbeispiel?

Z. B. wenn Sie die obigen Informationen verwenden, was erhalten Sie?

1 „Gefällt mir“

Entschuldigung, ich bin derzeit nicht in der Lage, Ihnen das mitzuteilen, da Zeitzonen nervig sind. Es ist hier sehr spät und ich könnte das erst am nächsten Tag tun.

Ich habe getan, was Sie verlangt haben. Das Passwort lautet swordfish#98765.

Datenbankeintrag:

discourse=> SELECT password_hash, salt, password_algorithm FROM users WHERE id=1;
                          password_hash                           |               salt               |      password_algorithm
------------------------------------------------------------------+----------------------------------+-------------------------------
 db3f0829e66336323e81110a1792a76000b9c60605e1fa6964797ea1b07c33c6 | 0d079078e220158011afaf497794166d | $pbkdf2-sha256$i=600000,l=32$
(1 row)

OpenSSL:

/var/discourse# openssl kdf \
> -kdfopt pass:'swordfish#98765' \
> -kdfopt salt:0d079078e220158011afaf497794166d \
> -kdfopt digest:SHA2-256 \
> -kdfopt iter:600000 \
> -keylen 32 \
> PBKDF2 \
> | tr -d : | tr '[:upper:]' '[:lower:]'
db3f0829e66336323e81110a1792a76000b9c60605e1fa6964797ea1b07c33c6

Go-Code:

var userId int
var hash string
var salt string
var active bool

row := s.Database.QueryRow(`
	SELECT u.id, u.password_hash, u.salt, u.active
	FROM users AS u
	INNER JOIN user_emails AS ue ON u.id = ue.user_id
	WHERE ue.email = $1;`,
email,
)

if err := row.Scan(&userId, &hash, &salt, &active); err != nil {
	// Fehlerbehandlung...
}

hashBytes, err := hex.DecodeString(hash)
if err != nil {
	// Fehlerbehandlung...
}

saltBytes, err := hex.DecodeString(salt)
if err != nil {
	// Fehlerbehandlung...
}

key := pbkdf2.Key([]byte(password), saltBytes, 600000, 32, sha256.New)

fmt.Printf("salt: %v\n", salt)
fmt.Printf("hash: %v\n", hash)
fmt.Printf("hex.EncodeToString(key): %v\n", hex.EncodeToString(key))

Ausgabe des obigen Codes:

salt: 0d079078e220158011afaf497794166d
hash: db3f0829e66336323e81110a1792a76000b9c60605e1fa6964797ea1b07c33c6
hex.EncodeToString(key): b378c12d96ac62a6099fc674d334f0793e6294f7927da0badc811e794a960802

Lass gut sein. Ich musste die Hex-Darstellung des Salzes als Argument verwenden, nicht das dekodierte Salz, wie ich es im obigen Beitrag getan habe. Jetzt sind die Hashes gleich.

5 „Gefällt mir“

Das war auch meine Theorie! Ich habe zuerst denselben Fehler gemacht.

1 „Gefällt mir“

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.